blob: 62c38aa57f3b6aa3e80e78baf7f99dc38d0c184f [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000119MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
120 JSObject* boilerplate) {
121 StackLimitCheck check(isolate);
122 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 JSObject* copy = JSObject::cast(result);
130
131 // Deep copy local properties.
132 if (copy->HasFastProperties()) {
133 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 for (int i = 0; i < properties->length(); i++) {
135 Object* value = properties->get(i);
136 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 }
143 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000144 int nof = copy->map()->inobject_properties();
145 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 Object* value = copy->InObjectPropertyAt(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
155 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 if (!maybe_result->ToObject(&result)) return maybe_result;
159 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 FixedArray* names = FixedArray::cast(result);
161 copy->GetLocalPropertyNames(names, 0);
162 for (int i = 0; i < names->length(); i++) {
163 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000164 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000166 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000167 // Only deep copy fields from the object literal expression.
168 // In particular, don't try to copy the length attribute of
169 // an array.
170 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000171 Object* value =
172 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000174 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000175 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 if (!maybe_result->ToObject(&result)) return maybe_result;
177 }
178 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000179 // Creating object copy for literals. No strict mode needed.
180 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000181 if (!maybe_result->ToObject(&result)) return maybe_result;
182 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000183 }
184 }
185 }
186
187 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000188 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000189 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000190 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000191 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000192 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000193 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 if (elements->map() == heap->fixed_cow_array_map()) {
195 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196#ifdef DEBUG
197 for (int i = 0; i < elements->length(); i++) {
198 ASSERT(!elements->get(i)->IsJSObject());
199 }
200#endif
201 } else {
202 for (int i = 0; i < elements->length(); i++) {
203 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000204 ASSERT(value->IsSmi() ||
205 value->IsTheHole() ||
206 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207 if (value->IsJSObject()) {
208 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000213 elements->set(i, result);
214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000215 }
216 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000219 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000220 NumberDictionary* element_dictionary = copy->element_dictionary();
221 int capacity = element_dictionary->Capacity();
222 for (int i = 0; i < capacity; i++) {
223 Object* k = element_dictionary->KeyAt(i);
224 if (element_dictionary->IsKey(k)) {
225 Object* value = element_dictionary->ValueAt(i);
226 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000227 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
229 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000230 if (!maybe_result->ToObject(&result)) return maybe_result;
231 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000232 element_dictionary->ValueAtPut(i, result);
233 }
234 }
235 }
236 break;
237 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000238 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000239 UNIMPLEMENTED();
240 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000241 case EXTERNAL_PIXEL_ELEMENTS:
242 case EXTERNAL_BYTE_ELEMENTS:
243 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
244 case EXTERNAL_SHORT_ELEMENTS:
245 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
246 case EXTERNAL_INT_ELEMENTS:
247 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
248 case EXTERNAL_FLOAT_ELEMENTS:
249 case EXTERNAL_DOUBLE_ELEMENTS:
250 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000251 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000253 }
254 return copy;
255}
256
257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000258RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000259 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000261}
262
263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000264RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000266 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267}
268
269
ager@chromium.org236ad962008-09-25 09:45:57 +0000270static Handle<Map> ComputeObjectLiteralMap(
271 Handle<Context> context,
272 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000273 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000275 int properties_length = constant_properties->length();
276 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000278 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000279 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000280 for (int p = 0; p != properties_length; p += 2) {
281 Object* key = constant_properties->get(p);
282 uint32_t element_index = 0;
283 if (key->IsSymbol()) {
284 number_of_symbol_keys++;
285 } else if (key->ToArrayIndex(&element_index)) {
286 // An index key does not require space in the property backing store.
287 number_of_properties--;
288 } else {
289 // Bail out as a non-symbol non-index key makes caching impossible.
290 // ASSERT to make sure that the if condition after the loop is false.
291 ASSERT(number_of_symbol_keys != number_of_properties);
292 break;
293 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000294 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000295 // If we only have symbols and array indices among keys then we can
296 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000297 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000298 if ((number_of_symbol_keys == number_of_properties) &&
299 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Handle<FixedArray> keys =
302 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000303 if (number_of_symbol_keys > 0) {
304 int index = 0;
305 for (int p = 0; p < properties_length; p += 2) {
306 Object* key = constant_properties->get(p);
307 if (key->IsSymbol()) {
308 keys->set(index++, key);
309 }
310 }
311 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000313 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000315 }
316 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000317 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000319 Handle<Map>(context->object_function()->initial_map()),
320 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000321}
322
323
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000324static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326 Handle<FixedArray> literals,
327 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329
330static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000333 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000334 bool should_have_fast_elements,
335 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000336 // Get the global context from the literals array. This is the
337 // context in which the function was created and we use the object
338 // function from this context to create the object literal. We do
339 // not use the object function from the current global context
340 // because this might be the object function from another context
341 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000342 Handle<Context> context =
343 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 // In case we have function literals, we want the object to be in
346 // slow properties mode for now. We don't go in the map cache because
347 // maps with constant functions can't be shared if the functions are
348 // not the same (which is the common case).
349 bool is_result_from_cache = false;
350 Handle<Map> map = has_function_literal
351 ? Handle<Map>(context->object_function()->initial_map())
352 : ComputeObjectLiteralMap(context,
353 constant_properties,
354 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000357
358 // Normalize the elements of the boilerplate to save space if needed.
359 if (!should_have_fast_elements) NormalizeElements(boilerplate);
360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 // Add the constant properties to the boilerplate.
362 int length = constant_properties->length();
363 bool should_transform =
364 !is_result_from_cache && boilerplate->HasFastProperties();
365 if (should_transform || has_function_literal) {
366 // Normalize the properties of object to avoid n^2 behavior
367 // when extending the object multiple properties. Indicate the number of
368 // properties to be added.
369 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
370 }
371
372 for (int index = 0; index < length; index +=2) {
373 Handle<Object> key(constant_properties->get(index+0), isolate);
374 Handle<Object> value(constant_properties->get(index+1), isolate);
375 if (value->IsFixedArray()) {
376 // The value contains the constant_properties of a
377 // simple object or array literal.
378 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
379 value = CreateLiteralBoilerplate(isolate, literals, array);
380 if (value.is_null()) return value;
381 }
382 Handle<Object> result;
383 uint32_t element_index = 0;
384 if (key->IsSymbol()) {
385 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
386 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000387 result = SetOwnElement(boilerplate,
388 element_index,
389 value,
390 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000392 Handle<String> name(String::cast(*key));
393 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000394 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
395 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 } else if (key->ToArrayIndex(&element_index)) {
398 // Array index (uint32).
399 result = SetOwnElement(boilerplate,
400 element_index,
401 value,
402 kNonStrictMode);
403 } else {
404 // Non-uint32 number.
405 ASSERT(key->IsNumber());
406 double num = key->Number();
407 char arr[100];
408 Vector<char> buffer(arr, ARRAY_SIZE(arr));
409 const char* str = DoubleToCString(num, buffer);
410 Handle<String> name =
411 isolate->factory()->NewStringFromAscii(CStrVector(str));
412 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
413 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 // If setting the property on the boilerplate throws an
416 // exception, the exception is converted to an empty handle in
417 // the handle based operations. In that case, we need to
418 // convert back to an exception.
419 if (result.is_null()) return result;
420 }
421
422 // Transform to fast properties if necessary. For object literals with
423 // containing function literals we defer this operation until after all
424 // computed properties have been assigned so that we can generate
425 // constant function properties.
426 if (should_transform && !has_function_literal) {
427 TransformToFastProperties(boilerplate,
428 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 }
430
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000431 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000432}
433
434
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000435static const int kSmiOnlyLiteralMinimumLength = 1024;
436
437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 Handle<FixedArray> literals,
441 Handle<FixedArray> elements) {
442 // Create the JSArray.
443 Handle<JSFunction> constructor(
444 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000445 Handle<JSArray> object =
446 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000447
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000448 ElementsKind constant_elements_kind =
449 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
450 Handle<FixedArrayBase> constant_elements_values(
451 FixedArrayBase::cast(elements->get(1)));
452
453 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
454 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
455 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
456 constant_elements_kind > object->GetElementsKind();
457
458 if (!FLAG_smi_only_arrays &&
459 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
460 constant_elements_kind != object->GetElementsKind()) {
461 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000462 }
463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 // If the ElementsKind of the constant values of the array literal are less
465 // specific than the ElementsKind of the boilerplate array object, change the
466 // boilerplate array object's map to reflect that kind.
467 if (allow_literal_kind_transition) {
468 Handle<Map> transitioned_array_map =
469 isolate->factory()->GetElementsTransitionMap(object,
470 constant_elements_kind);
471 object->set_map(*transitioned_array_map);
472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000473
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 Handle<FixedArrayBase> copied_elements_values;
475 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 ASSERT(FLAG_smi_only_arrays);
477 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
478 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000479 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
481 constant_elements_kind == FAST_ELEMENTS);
482 const bool is_cow =
483 (constant_elements_values->map() ==
484 isolate->heap()->fixed_cow_array_map());
485 if (is_cow) {
486 copied_elements_values = constant_elements_values;
487#if DEBUG
488 Handle<FixedArray> fixed_array_values =
489 Handle<FixedArray>::cast(copied_elements_values);
490 for (int i = 0; i < fixed_array_values->length(); i++) {
491 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
492 }
493#endif
494 } else {
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(constant_elements_values);
497 Handle<FixedArray> fixed_array_values_copy =
498 isolate->factory()->CopyFixedArray(fixed_array_values);
499 copied_elements_values = fixed_array_values_copy;
500 for (int i = 0; i < fixed_array_values->length(); i++) {
501 Object* current = fixed_array_values->get(i);
502 if (current->IsFixedArray()) {
503 // The value contains the constant_properties of a
504 // simple object or array literal.
505 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
506 Handle<Object> result =
507 CreateLiteralBoilerplate(isolate, literals, fa);
508 if (result.is_null()) return result;
509 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000510 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000511 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 }
513 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000514 object->set_elements(*copied_elements_values);
515 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 return object;
517}
518
519
520static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 Handle<FixedArray> literals,
523 Handle<FixedArray> array) {
524 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000526 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 return CreateObjectLiteralBoilerplate(isolate,
529 literals,
530 elements,
531 true,
532 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000533 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return CreateObjectLiteralBoilerplate(isolate,
535 literals,
536 elements,
537 false,
538 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000541 default:
542 UNREACHABLE();
543 return Handle<Object>::null();
544 }
545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000549 // Takes a FixedArray of elements containing the literal elements of
550 // the array literal and produces JSArray with those elements.
551 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000552 // which contains the context from which to get the Array function
553 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000555 ASSERT(args.length() == 3);
556 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000557 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000558 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 Handle<Object> object =
561 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000562 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000564 // Update the functions literal and return the boilerplate.
565 literals->set(literals_index, *object);
566 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567}
568
569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000570RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000572 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000573 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000574 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000576 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
578 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579
580 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000581 Handle<Object> boilerplate(literals->get(literals_index), isolate);
582 if (*boilerplate == isolate->heap()->undefined_value()) {
583 boilerplate = CreateObjectLiteralBoilerplate(isolate,
584 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000585 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 should_have_fast_elements,
587 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588 if (boilerplate.is_null()) return Failure::Exception();
589 // Update the functions literal and return the boilerplate.
590 literals->set(literals_index, *boilerplate);
591 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000592 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593}
594
595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000596RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000598 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000600 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000602 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
604 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000605
606 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 Handle<Object> boilerplate(literals->get(literals_index), isolate);
608 if (*boilerplate == isolate->heap()->undefined_value()) {
609 boilerplate = CreateObjectLiteralBoilerplate(isolate,
610 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000611 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000612 should_have_fast_elements,
613 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614 if (boilerplate.is_null()) return Failure::Exception();
615 // Update the functions literal and return the boilerplate.
616 literals->set(literals_index, *boilerplate);
617 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619}
620
621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000622RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000623 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624 ASSERT(args.length() == 3);
625 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000626 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000627 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
628
629 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000630 Handle<Object> boilerplate(literals->get(literals_index), isolate);
631 if (*boilerplate == isolate->heap()->undefined_value()) {
632 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000633 if (boilerplate.is_null()) return Failure::Exception();
634 // Update the functions literal and return the boilerplate.
635 literals->set(literals_index, *boilerplate);
636 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000637 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638}
639
640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000641RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000643 ASSERT(args.length() == 3);
644 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000645 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000646 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
647
648 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000649 Handle<Object> boilerplate(literals->get(literals_index), isolate);
650 if (*boilerplate == isolate->heap()->undefined_value()) {
651 boilerplate = 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);
703 CONVERT_CHECKED(JSProxy, proxy, args[0]);
704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
710 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
717 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
718 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);
724 CONVERT_CHECKED(JSProxy, proxy, args[0]);
725 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);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 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);
743 CONVERT_ARG_CHECKED(JSSet, holder, 0);
744 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);
755 CONVERT_ARG_CHECKED(JSSet, holder, 0);
756 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);
765 CONVERT_ARG_CHECKED(JSSet, holder, 0);
766 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);
777 CONVERT_ARG_CHECKED(JSMap, holder, 0);
778 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);
787 CONVERT_ARG_CHECKED(JSMap, holder, 0);
788 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);
796 CONVERT_ARG_CHECKED(JSMap, holder, 0);
797 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);
809 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
810 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);
821 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
823 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);
830 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000831 CONVERT_ARG_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);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000852 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
853 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
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000886RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000887 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000888 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000889 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000890 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891}
892
893
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000894// Recursively traverses hidden prototypes if property is not found
895static void GetOwnPropertyImplementation(JSObject* obj,
896 String* name,
897 LookupResult* result) {
898 obj->LocalLookupRealNamedProperty(name, result);
899
900 if (!result->IsProperty()) {
901 Object* proto = obj->GetPrototype();
902 if (proto->IsJSObject() &&
903 JSObject::cast(proto)->map()->is_hidden_prototype())
904 GetOwnPropertyImplementation(JSObject::cast(proto),
905 name, result);
906 }
907}
908
909
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000910static bool CheckAccessException(LookupResult* result,
911 v8::AccessType access_type) {
912 if (result->type() == CALLBACKS) {
913 Object* callback = result->GetCallbackObject();
914 if (callback->IsAccessorInfo()) {
915 AccessorInfo* info = AccessorInfo::cast(callback);
916 bool can_access =
917 (access_type == v8::ACCESS_HAS &&
918 (info->all_can_read() || info->all_can_write())) ||
919 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
920 (access_type == v8::ACCESS_SET && info->all_can_write());
921 return can_access;
922 }
923 }
924
925 return false;
926}
927
928
929static bool CheckAccess(JSObject* obj,
930 String* name,
931 LookupResult* result,
932 v8::AccessType access_type) {
933 ASSERT(result->IsProperty());
934
935 JSObject* holder = result->holder();
936 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000937 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000938 while (true) {
939 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000940 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000941 // Access check callback denied the access, but some properties
942 // can have a special permissions which override callbacks descision
943 // (currently see v8::AccessControl).
944 break;
945 }
946
947 if (current == holder) {
948 return true;
949 }
950
951 current = JSObject::cast(current->GetPrototype());
952 }
953
954 // API callbacks can have per callback access exceptions.
955 switch (result->type()) {
956 case CALLBACKS: {
957 if (CheckAccessException(result, access_type)) {
958 return true;
959 }
960 break;
961 }
962 case INTERCEPTOR: {
963 // If the object has an interceptor, try real named properties.
964 // Overwrite the result to fetch the correct property later.
965 holder->LookupRealNamedProperty(name, result);
966 if (result->IsProperty()) {
967 if (CheckAccessException(result, access_type)) {
968 return true;
969 }
970 }
971 break;
972 }
973 default:
974 break;
975 }
976
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000977 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000978 return false;
979}
980
981
982// TODO(1095): we should traverse hidden prototype hierachy as well.
983static bool CheckElementAccess(JSObject* obj,
984 uint32_t index,
985 v8::AccessType access_type) {
986 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000987 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000988 return false;
989 }
990
991 return true;
992}
993
994
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000995// Enumerator used as indices into the array returned from GetOwnProperty
996enum PropertyDescriptorIndices {
997 IS_ACCESSOR_INDEX,
998 VALUE_INDEX,
999 GETTER_INDEX,
1000 SETTER_INDEX,
1001 WRITABLE_INDEX,
1002 ENUMERABLE_INDEX,
1003 CONFIGURABLE_INDEX,
1004 DESCRIPTOR_SIZE
1005};
1006
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001007// Returns an array with the property description:
1008// if args[1] is not a property on args[0]
1009// returns undefined
1010// if args[1] is a data property on args[0]
1011// [false, value, Writeable, Enumerable, Configurable]
1012// if args[1] is an accessor on args[0]
1013// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001014RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001015 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001016 Heap* heap = isolate->heap();
1017 HandleScope scope(isolate);
1018 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1019 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001020 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001021 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1022 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001023
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001024 // This could be an element.
1025 uint32_t index;
1026 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001027 switch (obj->HasLocalElement(index)) {
1028 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001030
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001031 case JSObject::STRING_CHARACTER_ELEMENT: {
1032 // Special handling of string objects according to ECMAScript 5
1033 // 15.5.5.2. Note that this might be a string object with elements
1034 // other than the actual string value. This is covered by the
1035 // subsequent cases.
1036 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1037 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001038 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001039
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001040 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001041 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 elms->set(WRITABLE_INDEX, heap->false_value());
1043 elms->set(ENUMERABLE_INDEX, heap->false_value());
1044 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001045 return *desc;
1046 }
1047
1048 case JSObject::INTERCEPTED_ELEMENT:
1049 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001050 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001051 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001053 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001054 elms->set(WRITABLE_INDEX, heap->true_value());
1055 elms->set(ENUMERABLE_INDEX, heap->true_value());
1056 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001057 return *desc;
1058 }
1059
1060 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001061 Handle<JSObject> holder = obj;
1062 if (obj->IsJSGlobalProxy()) {
1063 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001064 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001065 ASSERT(proto->IsJSGlobalObject());
1066 holder = Handle<JSObject>(JSObject::cast(proto));
1067 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001068 FixedArray* elements = FixedArray::cast(holder->elements());
1069 NumberDictionary* dictionary = NULL;
1070 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1071 dictionary = NumberDictionary::cast(elements->get(1));
1072 } else {
1073 dictionary = NumberDictionary::cast(elements);
1074 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001075 int entry = dictionary->FindEntry(index);
1076 ASSERT(entry != NumberDictionary::kNotFound);
1077 PropertyDetails details = dictionary->DetailsAt(entry);
1078 switch (details.type()) {
1079 case CALLBACKS: {
1080 // This is an accessor property with getter and/or setter.
1081 FixedArray* callbacks =
1082 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001084 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1085 elms->set(GETTER_INDEX, callbacks->get(0));
1086 }
1087 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1088 elms->set(SETTER_INDEX, callbacks->get(1));
1089 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 break;
1091 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001092 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001093 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001094 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001095 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001096 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001097 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001099 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001100 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001101 default:
1102 UNREACHABLE();
1103 break;
1104 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001105 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1106 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001107 return *desc;
1108 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001109 }
1110 }
1111
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001112 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001113 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001114
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001115 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001116 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001117 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001118
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001119 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001120 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001121 }
1122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001123 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1124 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001125
1126 bool is_js_accessor = (result.type() == CALLBACKS) &&
1127 (result.GetCallbackObject()->IsFixedArray());
1128
1129 if (is_js_accessor) {
1130 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001132
1133 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1134 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1135 elms->set(GETTER_INDEX, structure->get(0));
1136 }
1137 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1138 elms->set(SETTER_INDEX, structure->get(1));
1139 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001140 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001141 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1142 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001143
1144 PropertyAttributes attrs;
1145 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001146 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001147 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1148 if (!maybe_value->ToObject(&value)) return maybe_value;
1149 }
1150 elms->set(VALUE_INDEX, value);
1151 }
1152
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001153 return *desc;
1154}
1155
1156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001157RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001158 ASSERT(args.length() == 1);
1159 CONVERT_CHECKED(JSObject, obj, args[0]);
1160 return obj->PreventExtensions();
1161}
1162
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001164RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001165 ASSERT(args.length() == 1);
1166 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001167 if (obj->IsJSGlobalProxy()) {
1168 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001170 ASSERT(proto->IsJSGlobalObject());
1171 obj = JSObject::cast(proto);
1172 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001173 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001174}
1175
1176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001177RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001178 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001180 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1181 CONVERT_ARG_CHECKED(String, pattern, 1);
1182 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001183 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1184 if (result.is_null()) return Failure::Exception();
1185 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186}
1187
1188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001189RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001190 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001192 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001193 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001194}
1195
1196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001197RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 ASSERT(args.length() == 1);
1199 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001200 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001201 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202}
1203
1204
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001205RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001206 ASSERT(args.length() == 2);
1207 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001208 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001209 int index = field->value();
1210 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1211 InstanceType type = templ->map()->instance_type();
1212 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1213 type == OBJECT_TEMPLATE_INFO_TYPE);
1214 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001215 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001216 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1217 } else {
1218 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1219 }
1220 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221}
1222
1223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001224RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001225 ASSERT(args.length() == 1);
1226 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001227 Map* old_map = object->map();
1228 bool needs_access_checks = old_map->is_access_check_needed();
1229 if (needs_access_checks) {
1230 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001231 Object* new_map;
1232 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1233 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1234 }
ager@chromium.org32912102009-01-16 10:38:43 +00001235
1236 Map::cast(new_map)->set_is_access_check_needed(false);
1237 object->set_map(Map::cast(new_map));
1238 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001239 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001240}
1241
1242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001243RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001244 ASSERT(args.length() == 1);
1245 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001246 Map* old_map = object->map();
1247 if (!old_map->is_access_check_needed()) {
1248 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001249 Object* new_map;
1250 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1251 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1252 }
ager@chromium.org32912102009-01-16 10:38:43 +00001253
1254 Map::cast(new_map)->set_is_access_check_needed(true);
1255 object->set_map(Map::cast(new_map));
1256 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001258}
1259
1260
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261static Failure* ThrowRedeclarationError(Isolate* isolate,
1262 const char* type,
1263 Handle<String> name) {
1264 HandleScope scope(isolate);
1265 Handle<Object> type_handle =
1266 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 Handle<Object> args[2] = { type_handle, name };
1268 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1270 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001271}
1272
1273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001274RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001275 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001276 HandleScope scope(isolate);
1277 Handle<GlobalObject> global = Handle<GlobalObject>(
1278 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279
ager@chromium.org3811b432009-10-28 14:53:37 +00001280 Handle<Context> context = args.at<Context>(0);
1281 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001282 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 // Traverse the name/value pairs and set the properties.
1285 int length = pairs->length();
1286 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290
1291 // We have to declare a global const property. To capture we only
1292 // assign to it when evaluating the assignment for "const x =
1293 // <expr>" the initial value is the hole.
1294 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001295 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 if (value->IsUndefined() || is_const_property) {
1297 // Lookup the property in the global object, and don't set the
1298 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001299 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 global->Lookup(*name, &lookup);
1301 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001302 // We found an existing property. Unless it was an interceptor
1303 // that claims the property is absent, skip this declaration.
1304 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 continue;
1306 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001307 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1308 if (attributes != ABSENT) {
1309 continue;
1310 }
1311 // Fall-through and introduce the absent property by using
1312 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 }
1314 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001315 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001317 Handle<SharedFunctionInfo> shared =
1318 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001320 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1321 context,
1322 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323 value = function;
1324 }
1325
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001326 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 global->LocalLookup(*name, &lookup);
1328
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001329 // Compute the property attributes. According to ECMA-262, section
1330 // 13, page 71, the property must be read-only and
1331 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1332 // property as read-only, so we don't either.
1333 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001334 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001335 attr |= DONT_DELETE;
1336 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001337 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001338 if (is_const_property || (is_native && is_function_declaration)) {
1339 attr |= READ_ONLY;
1340 }
1341
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001342 // Safari does not allow the invocation of callback setters for
1343 // function declarations. To mimic this behavior, we do not allow
1344 // the invocation of setters for function values. This makes a
1345 // difference for global functions with the same names as event
1346 // handlers such as "function onload() {}". Firefox does call the
1347 // onload setter in those case and Safari does not. We follow
1348 // Safari for compatibility.
1349 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 // Do not change DONT_DELETE to false from true.
1351 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001352 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001353 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001354 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 RETURN_IF_EMPTY_HANDLE(isolate,
1357 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001358 name,
1359 value,
1360 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001362 StrictModeFlag strict_mode = DeclareGlobalsStrictModeFlag::decode(flags);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 RETURN_IF_EMPTY_HANDLE(isolate,
1364 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001365 name,
1366 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001367 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001368 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 }
1370 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001371
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001372 ASSERT(!isolate->has_pending_exception());
1373 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001374}
1375
1376
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001377RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001378 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001379 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001380
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001381 // Declarations are always made in a function or global context. In the
1382 // case of eval code, the context passed is the context of the caller,
1383 // which may be some nested context and not the declaration context.
1384 RUNTIME_ASSERT(args[0]->IsContext());
1385 Handle<Context> context(Context::cast(args[0])->declaration_context());
1386
ager@chromium.org7c537e22008-10-16 08:43:32 +00001387 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001388 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001389 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001390 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001392 int index;
1393 PropertyAttributes attributes;
1394 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001395 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001396 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001397 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
1399 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001400 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001401 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1402 // Functions are not read-only.
1403 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1404 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406 }
1407
1408 // Initialize it if necessary.
1409 if (*initial_value != NULL) {
1410 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001411 ASSERT(holder.is_identical_to(context));
1412 if (((attributes & READ_ONLY) == 0) ||
1413 context->get(index)->IsTheHole()) {
1414 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 }
1416 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001417 // Slow case: The property is in the context extension object of a
1418 // function context or the global object of a global context.
1419 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001420 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001422 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423 }
1424 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001427 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001428 // "declared" in the function context's extension context or as a
1429 // property of the the global object.
1430 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001431 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001432 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001433 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001434 // Context extension objects are allocated lazily.
1435 ASSERT(context->IsFunctionContext());
1436 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001437 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001438 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001439 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001440 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441
ager@chromium.org7c537e22008-10-16 08:43:32 +00001442 // Declare the property by setting it to the initial value if provided,
1443 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1444 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001445 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001447 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001448 // Declaring a const context slot is a conflicting declaration if
1449 // there is a callback with that name in a prototype. It is
1450 // allowed to introduce const variables in
1451 // JSContextExtensionObjects. They are treated specially in
1452 // SetProperty and no setters are invoked for those since they are
1453 // not real JSObjects.
1454 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001455 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001456 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001457 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001458 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001459 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001460 }
1461 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001462 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001463 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001464 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001465 }
1466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468}
1469
1470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001471RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001473 // args[0] == name
1474 // args[1] == strict_mode
1475 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476
1477 // Determine if we need to assign to the variable if it already
1478 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001479 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1480 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481
1482 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001483 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001484 RUNTIME_ASSERT(args[1]->IsSmi());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001485 CONVERT_STRICT_MODE_ARG(strict_mode, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486
1487 // According to ECMA-262, section 12.2, page 62, the property must
1488 // not be deletable.
1489 PropertyAttributes attributes = DONT_DELETE;
1490
1491 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001492 // there, there is a property with this name in the prototype chain.
1493 // We follow Safari and Firefox behavior and only set the property
1494 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001495 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001496 // Note that objects can have hidden prototypes, so we need to traverse
1497 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001499 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001500 while (object->IsJSObject() &&
1501 JSObject::cast(object)->map()->is_hidden_prototype()) {
1502 JSObject* raw_holder = JSObject::cast(object);
1503 raw_holder->LocalLookup(*name, &lookup);
1504 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1505 HandleScope handle_scope(isolate);
1506 Handle<JSObject> holder(raw_holder);
1507 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1508 // Update the raw pointer in case it's changed due to GC.
1509 raw_holder = *holder;
1510 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1511 // Found an interceptor that's not read only.
1512 if (assign) {
1513 return raw_holder->SetProperty(
1514 &lookup, *name, args[2], attributes, strict_mode);
1515 } else {
1516 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001517 }
1518 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001519 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001520 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 }
1522
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001523 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001524 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001525 if (assign) {
1526 return global->SetProperty(*name, args[2], attributes, strict_mode);
1527 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001528 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529}
1530
1531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001532RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001533 // All constants are declared with an initial value. The name
1534 // of the constant is the first argument and the initial value
1535 // is the second.
1536 RUNTIME_ASSERT(args.length() == 2);
1537 CONVERT_ARG_CHECKED(String, name, 0);
1538 Handle<Object> value = args.at<Object>(1);
1539
1540 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001541 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542
1543 // According to ECMA-262, section 12.2, page 62, the property must
1544 // not be deletable. Since it's a const, it must be READ_ONLY too.
1545 PropertyAttributes attributes =
1546 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1547
1548 // Lookup the property locally in the global object. If it isn't
1549 // there, we add the property and take special precautions to always
1550 // add it as a local property even in case of callbacks in the
1551 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001552 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001553 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 global->LocalLookup(*name, &lookup);
1555 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001556 return global->SetLocalPropertyIgnoreAttributes(*name,
1557 *value,
1558 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559 }
1560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001563 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001564 HandleScope handle_scope(isolate);
1565 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001567 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 // property through an interceptor and only do it if it's
1569 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001570 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 RETURN_IF_EMPTY_HANDLE(isolate,
1572 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001573 name,
1574 value,
1575 attributes,
1576 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 return *value;
1578 }
1579
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001580 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 // constant. For now, we determine this by checking if the
1582 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001583 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584 PropertyType type = lookup.type();
1585 if (type == FIELD) {
1586 FixedArray* properties = global->properties();
1587 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001588 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 properties->set(index, *value);
1590 }
1591 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001592 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1593 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001594 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 }
1596 } else {
1597 // Ignore re-initialization of constants that have already been
1598 // assigned a function value.
1599 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1600 }
1601
1602 // Use the set value as the result of the operation.
1603 return *value;
1604}
1605
1606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001607RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001608 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001609 ASSERT(args.length() == 3);
1610
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001611 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001614 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001615 RUNTIME_ASSERT(args[1]->IsContext());
1616 Handle<Context> context(Context::cast(args[1])->declaration_context());
1617
1618 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619
1620 int index;
1621 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001622 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001623 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001624 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001625 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001628 ASSERT(holder->IsContext());
1629 // Property was found in a context. Perform the assignment if we
1630 // found some non-constant or an uninitialized constant.
1631 Handle<Context> context = Handle<Context>::cast(holder);
1632 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1633 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634 }
1635 return *value;
1636 }
1637
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001638 // The property could not be found, we introduce it as a property of the
1639 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001640 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001641 Handle<JSObject> global = Handle<JSObject>(
1642 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001643 // Strict mode not needed (const disallowed in strict mode).
1644 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001646 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001647 return *value;
1648 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001650 // The property was present in some function's context extension object,
1651 // as a property on the subject of a with, or as a property of the global
1652 // object.
1653 //
1654 // In most situations, eval-introduced consts should still be present in
1655 // the context extension object. However, because declaration and
1656 // initialization are separate, the property might have been deleted
1657 // before we reach the initialization point.
1658 //
1659 // Example:
1660 //
1661 // function f() { eval("delete x; const x;"); }
1662 //
1663 // In that case, the initialization behaves like a normal assignment.
1664 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001665
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001666 if (*object == context->extension()) {
1667 // This is the property that was introduced by the const declaration.
1668 // Set it if it hasn't been set before. NOTE: We cannot use
1669 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001670 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001672 ASSERT(lookup.IsProperty()); // the property was declared
1673 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1674
1675 PropertyType type = lookup.type();
1676 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001677 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001678 int index = lookup.GetFieldIndex();
1679 if (properties->get(index)->IsTheHole()) {
1680 properties->set(index, *value);
1681 }
1682 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001683 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1684 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001685 }
1686 } else {
1687 // We should not reach here. Any real, named property should be
1688 // either a field or a dictionary slot.
1689 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690 }
1691 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001692 // The property was found on some other object. Set it if it is not a
1693 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001694 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001695 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001696 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001697 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001698 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 return *value;
1703}
1704
1705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001706RUNTIME_FUNCTION(MaybeObject*,
1707 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001708 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001709 ASSERT(args.length() == 2);
1710 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001711 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001712 if (object->HasFastProperties()) {
1713 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1714 }
1715 return *object;
1716}
1717
1718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001719RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001721 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001722 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1723 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001726 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001727 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001728 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001729 RUNTIME_ASSERT(index >= 0);
1730 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001732 Handle<Object> result = RegExpImpl::Exec(regexp,
1733 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001734 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001735 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001736 if (result.is_null()) return Failure::Exception();
1737 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001738}
1739
1740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001741RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001743 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001744 if (elements_count < 0 ||
1745 elements_count > FixedArray::kMaxLength ||
1746 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 Object* new_object;
1750 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1753 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1756 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1758 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001759 {
1760 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001762 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001764 }
1765 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001767 array->set_elements(elements);
1768 array->set_length(Smi::FromInt(elements_count));
1769 // Write in-object properties after the length of the array.
1770 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1771 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1772 return array;
1773}
1774
1775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001776RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777 AssertNoAllocation no_alloc;
1778 ASSERT(args.length() == 5);
1779 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1780 CONVERT_CHECKED(String, source, args[1]);
1781
1782 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001783 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001784
1785 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001786 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001787
1788 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790
1791 Map* map = regexp->map();
1792 Object* constructor = map->constructor();
1793 if (constructor->IsJSFunction() &&
1794 JSFunction::cast(constructor)->initial_map() == map) {
1795 // If we still have the original map, set in-object properties directly.
1796 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1797 // TODO(lrn): Consider skipping write barrier on booleans as well.
1798 // Both true and false should be in oldspace at all times.
1799 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1800 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1801 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1802 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1803 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001804 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001805 return regexp;
1806 }
1807
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001809 PropertyAttributes final =
1810 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1811 PropertyAttributes writable =
1812 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001814 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001815 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001816 source,
1817 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001818 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001819 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001820 global,
1821 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001822 ASSERT(!result->IsFailure());
1823 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001824 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001825 ignoreCase,
1826 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001827 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001828 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001829 multiline,
1830 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001831 ASSERT(!result->IsFailure());
1832 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001834 Smi::FromInt(0),
1835 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001836 ASSERT(!result->IsFailure());
1837 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001838 return regexp;
1839}
1840
1841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001842RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001844 ASSERT(args.length() == 1);
1845 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1846 // This is necessary to enable fast checks for absence of elements
1847 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001848 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001849 return Smi::FromInt(0);
1850}
1851
1852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1854 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001855 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001856 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1858 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1859 Handle<JSFunction> optimized =
1860 isolate->factory()->NewFunction(key,
1861 JS_OBJECT_TYPE,
1862 JSObject::kHeaderSize,
1863 code,
1864 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001865 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001866 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001867 return optimized;
1868}
1869
1870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001871RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001872 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001873 ASSERT(args.length() == 1);
1874 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1875
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001876 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1877 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1878 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1879 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1880 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1881 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1882 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001883
1884 return *holder;
1885}
1886
1887
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001888RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1889 NoHandleAllocation handle_free;
1890 ASSERT(args.length() == 1);
1891 CONVERT_CHECKED(JSFunction, function, args[0]);
1892 SharedFunctionInfo* shared = function->shared();
1893 if (shared->native() || shared->strict_mode()) {
1894 return isolate->heap()->undefined_value();
1895 }
1896 // Returns undefined for strict or native functions, or
1897 // the associated global receiver for "normal" functions.
1898
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001899 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001900 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001901 return global_context->global()->global_receiver();
1902}
1903
1904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001905RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001906 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001907 ASSERT(args.length() == 4);
1908 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001909 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001910 Handle<String> pattern = args.at<String>(2);
1911 Handle<String> flags = args.at<String>(3);
1912
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001913 // Get the RegExp function from the context in the literals array.
1914 // This is the RegExp function from the context in which the
1915 // function was created. We do not use the RegExp function from the
1916 // current global context because this might be the RegExp function
1917 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001918 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001919 Handle<JSFunction>(
1920 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001921 // Compute the regular expression literal.
1922 bool has_pending_exception;
1923 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001924 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1925 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001927 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001928 return Failure::Exception();
1929 }
1930 literals->set(index, *regexp);
1931 return *regexp;
1932}
1933
1934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001935RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001936 NoHandleAllocation ha;
1937 ASSERT(args.length() == 1);
1938
1939 CONVERT_CHECKED(JSFunction, f, args[0]);
1940 return f->shared()->name();
1941}
1942
1943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001944RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001945 NoHandleAllocation ha;
1946 ASSERT(args.length() == 2);
1947
1948 CONVERT_CHECKED(JSFunction, f, args[0]);
1949 CONVERT_CHECKED(String, name, args[1]);
1950 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001951 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001952}
1953
1954
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001955RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1956 NoHandleAllocation ha;
1957 ASSERT(args.length() == 1);
1958 CONVERT_CHECKED(JSFunction, f, args[0]);
1959 return isolate->heap()->ToBoolean(
1960 f->shared()->name_should_print_as_anonymous());
1961}
1962
1963
1964RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1965 NoHandleAllocation ha;
1966 ASSERT(args.length() == 1);
1967 CONVERT_CHECKED(JSFunction, f, args[0]);
1968 f->shared()->set_name_should_print_as_anonymous(true);
1969 return isolate->heap()->undefined_value();
1970}
1971
1972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001973RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001974 NoHandleAllocation ha;
1975 ASSERT(args.length() == 1);
1976
1977 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001978 Object* obj = f->RemovePrototype();
1979 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001980
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001981 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001982}
1983
1984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001985RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001986 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001987 ASSERT(args.length() == 1);
1988
1989 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1991 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001992
1993 return *GetScriptWrapper(Handle<Script>::cast(script));
1994}
1995
1996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001997RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001998 NoHandleAllocation ha;
1999 ASSERT(args.length() == 1);
2000
2001 CONVERT_CHECKED(JSFunction, f, args[0]);
2002 return f->shared()->GetSourceCode();
2003}
2004
2005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002006RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002007 NoHandleAllocation ha;
2008 ASSERT(args.length() == 1);
2009
2010 CONVERT_CHECKED(JSFunction, fun, args[0]);
2011 int pos = fun->shared()->start_position();
2012 return Smi::FromInt(pos);
2013}
2014
2015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002016RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002017 ASSERT(args.length() == 2);
2018
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002019 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002020 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2021
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002022 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2023
2024 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002025 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002026}
2027
2028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002029RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 NoHandleAllocation ha;
2031 ASSERT(args.length() == 2);
2032
2033 CONVERT_CHECKED(JSFunction, fun, args[0]);
2034 CONVERT_CHECKED(String, name, args[1]);
2035 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002036 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002041 NoHandleAllocation ha;
2042 ASSERT(args.length() == 2);
2043
2044 CONVERT_CHECKED(JSFunction, fun, args[0]);
2045 CONVERT_CHECKED(Smi, length, args[1]);
2046 fun->shared()->set_length(length->value());
2047 return length;
2048}
2049
2050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002051RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002052 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053 ASSERT(args.length() == 2);
2054
2055 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002056 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002057 Object* obj;
2058 { MaybeObject* maybe_obj =
2059 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2060 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2061 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062 return args[0]; // return TOS
2063}
2064
2065
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002066RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2067 NoHandleAllocation ha;
2068 RUNTIME_ASSERT(args.length() == 1);
2069 CONVERT_CHECKED(JSFunction, function, args[0]);
2070
2071 MaybeObject* maybe_name =
2072 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2073 String* name;
2074 if (!maybe_name->To(&name)) return maybe_name;
2075
2076 if (function->HasFastProperties()) {
2077 // Construct a new field descriptor with updated attributes.
2078 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2079 int index = instance_desc->Search(name);
2080 ASSERT(index != DescriptorArray::kNotFound);
2081 PropertyDetails details(instance_desc->GetDetails(index));
2082 CallbacksDescriptor new_desc(name,
2083 instance_desc->GetValue(index),
2084 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2085 details.index());
2086 // Construct a new field descriptors array containing the new descriptor.
2087 Object* descriptors_unchecked;
2088 { MaybeObject* maybe_descriptors_unchecked =
2089 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2090 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2091 return maybe_descriptors_unchecked;
2092 }
2093 }
2094 DescriptorArray* new_descriptors =
2095 DescriptorArray::cast(descriptors_unchecked);
2096 // Create a new map featuring the new field descriptors array.
2097 Object* map_unchecked;
2098 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2099 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2100 return maybe_map_unchecked;
2101 }
2102 }
2103 Map* new_map = Map::cast(map_unchecked);
2104 new_map->set_instance_descriptors(new_descriptors);
2105 function->set_map(new_map);
2106 } else { // Dictionary properties.
2107 // Directly manipulate the property details.
2108 int entry = function->property_dictionary()->FindEntry(name);
2109 ASSERT(entry != StringDictionary::kNotFound);
2110 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2111 PropertyDetails new_details(
2112 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2113 details.type(),
2114 details.index());
2115 function->property_dictionary()->DetailsAtPut(entry, new_details);
2116 }
2117 return function;
2118}
2119
2120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002121RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002122 NoHandleAllocation ha;
2123 ASSERT(args.length() == 1);
2124
2125 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002126 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002127}
2128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002130RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002131 NoHandleAllocation ha;
2132 ASSERT(args.length() == 1);
2133
2134 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002135 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002136}
2137
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002139RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002140 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002141 ASSERT(args.length() == 2);
2142
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002143 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002144 Handle<Object> code = args.at<Object>(1);
2145
2146 Handle<Context> context(target->context());
2147
2148 if (!code->IsNull()) {
2149 RUNTIME_ASSERT(code->IsJSFunction());
2150 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002151 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002152
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002153 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154 return Failure::Exception();
2155 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002156 // Since we don't store the source for this we should never
2157 // optimize this.
2158 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002159 // Set the code, scope info, formal parameter count,
2160 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002161 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002162 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002163 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002164 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002165 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002166 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002167 // Set the source code of the target function to undefined.
2168 // SetCode is only used for built-in constructors like String,
2169 // Array, and Object, and some web code
2170 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002171 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002172 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002173 // Clear the optimization hints related to the compiled code as these are no
2174 // longer valid when the code is overwritten.
2175 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002176 context = Handle<Context>(fun->context());
2177
2178 // Make sure we get a fresh copy of the literal vector to avoid
2179 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002180 int number_of_literals = fun->NumberOfLiterals();
2181 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002182 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002183 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002184 // Insert the object, regexp and array functions in the literals
2185 // array prefix. These are the functions that will be used when
2186 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002187 literals->set(JSFunction::kLiteralGlobalContextIndex,
2188 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002189 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002190 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002191 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002192
2193 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2194 isolate->logger()->LogExistingFunction(
2195 shared, Handle<Code>(shared->code()));
2196 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 }
2198
2199 target->set_context(*context);
2200 return *target;
2201}
2202
2203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002204RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002206 ASSERT(args.length() == 2);
2207 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002208 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002209 RUNTIME_ASSERT(num >= 0);
2210 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002211 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002212}
2213
2214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002215MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2216 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002217 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002218 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002219 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002220 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002221 }
2222 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002223 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002224}
2225
2226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002227RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002228 NoHandleAllocation ha;
2229 ASSERT(args.length() == 2);
2230
2231 CONVERT_CHECKED(String, subject, args[0]);
2232 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002233 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002234
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002235 uint32_t i = 0;
2236 if (index->IsSmi()) {
2237 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002238 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002239 i = value;
2240 } else {
2241 ASSERT(index->IsHeapNumber());
2242 double value = HeapNumber::cast(index)->value();
2243 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002244 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002245
2246 // Flatten the string. If someone wants to get a char at an index
2247 // in a cons string, it is likely that more indices will be
2248 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002249 Object* flat;
2250 { MaybeObject* maybe_flat = subject->TryFlatten();
2251 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2252 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002253 subject = String::cast(flat);
2254
2255 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002256 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002257 }
2258
2259 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002260}
2261
2262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002263RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002264 NoHandleAllocation ha;
2265 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002266 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002267}
2268
lrn@chromium.org25156de2010-04-06 13:10:27 +00002269
2270class FixedArrayBuilder {
2271 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2273 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002274 length_(0),
2275 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002276 // Require a non-zero initial size. Ensures that doubling the size to
2277 // extend the array will work.
2278 ASSERT(initial_capacity > 0);
2279 }
2280
2281 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2282 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002283 length_(0),
2284 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002285 // Require a non-zero initial size. Ensures that doubling the size to
2286 // extend the array will work.
2287 ASSERT(backing_store->length() > 0);
2288 }
2289
2290 bool HasCapacity(int elements) {
2291 int length = array_->length();
2292 int required_length = length_ + elements;
2293 return (length >= required_length);
2294 }
2295
2296 void EnsureCapacity(int elements) {
2297 int length = array_->length();
2298 int required_length = length_ + elements;
2299 if (length < required_length) {
2300 int new_length = length;
2301 do {
2302 new_length *= 2;
2303 } while (new_length < required_length);
2304 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002305 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002306 array_->CopyTo(0, *extended_array, 0, length_);
2307 array_ = extended_array;
2308 }
2309 }
2310
2311 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002312 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002313 ASSERT(length_ < capacity());
2314 array_->set(length_, value);
2315 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002316 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002317 }
2318
2319 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002320 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002321 ASSERT(length_ < capacity());
2322 array_->set(length_, value);
2323 length_++;
2324 }
2325
2326 Handle<FixedArray> array() {
2327 return array_;
2328 }
2329
2330 int length() {
2331 return length_;
2332 }
2333
2334 int capacity() {
2335 return array_->length();
2336 }
2337
2338 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002339 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002340 result_array->set_length(Smi::FromInt(length_));
2341 return result_array;
2342 }
2343
2344 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002345 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002346 target_array->set_length(Smi::FromInt(length_));
2347 return target_array;
2348 }
2349
2350 private:
2351 Handle<FixedArray> array_;
2352 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002353 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002354};
2355
2356
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002357// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002358const int kStringBuilderConcatHelperLengthBits = 11;
2359const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002360
2361template <typename schar>
2362static inline void StringBuilderConcatHelper(String*,
2363 schar*,
2364 FixedArray*,
2365 int);
2366
lrn@chromium.org25156de2010-04-06 13:10:27 +00002367typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2368 StringBuilderSubstringLength;
2369typedef BitField<int,
2370 kStringBuilderConcatHelperLengthBits,
2371 kStringBuilderConcatHelperPositionBits>
2372 StringBuilderSubstringPosition;
2373
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374
2375class ReplacementStringBuilder {
2376 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002377 ReplacementStringBuilder(Heap* heap,
2378 Handle<String> subject,
2379 int estimated_part_count)
2380 : heap_(heap),
2381 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002382 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002383 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002384 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002385 // Require a non-zero initial size. Ensures that doubling the size to
2386 // extend the array will work.
2387 ASSERT(estimated_part_count > 0);
2388 }
2389
lrn@chromium.org25156de2010-04-06 13:10:27 +00002390 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2391 int from,
2392 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 ASSERT(from >= 0);
2394 int length = to - from;
2395 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002396 if (StringBuilderSubstringLength::is_valid(length) &&
2397 StringBuilderSubstringPosition::is_valid(from)) {
2398 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2399 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002400 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002401 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002402 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002403 builder->Add(Smi::FromInt(-length));
2404 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002405 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002406 }
2407
2408
2409 void EnsureCapacity(int elements) {
2410 array_builder_.EnsureCapacity(elements);
2411 }
2412
2413
2414 void AddSubjectSlice(int from, int to) {
2415 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002416 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002417 }
2418
2419
2420 void AddString(Handle<String> string) {
2421 int length = string->length();
2422 ASSERT(length > 0);
2423 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002424 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002425 is_ascii_ = false;
2426 }
2427 IncrementCharacterCount(length);
2428 }
2429
2430
2431 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002432 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002433 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002434 }
2435
2436 Handle<String> joined_string;
2437 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002438 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 char* char_buffer = seq->GetChars();
2441 StringBuilderConcatHelper(*subject_,
2442 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002443 *array_builder_.array(),
2444 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002445 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002446 } else {
2447 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002448 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002449 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002450 uc16* char_buffer = seq->GetChars();
2451 StringBuilderConcatHelper(*subject_,
2452 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 *array_builder_.array(),
2454 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002455 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 }
2457 return joined_string;
2458 }
2459
2460
2461 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002462 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 V8::FatalProcessOutOfMemory("String.replace result too large.");
2464 }
2465 character_count_ += by;
2466 }
2467
lrn@chromium.org25156de2010-04-06 13:10:27 +00002468 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002469 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002470 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002471
lrn@chromium.org25156de2010-04-06 13:10:27 +00002472 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002473 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2474 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002475 }
2476
2477
ager@chromium.org04921a82011-06-27 13:21:41 +00002478 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2479 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 }
2481
2482
2483 void AddElement(Object* element) {
2484 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002485 ASSERT(array_builder_.capacity() > array_builder_.length());
2486 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002487 }
2488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002489 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002490 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002491 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002492 int character_count_;
2493 bool is_ascii_;
2494};
2495
2496
2497class CompiledReplacement {
2498 public:
2499 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002500 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002501
2502 void Compile(Handle<String> replacement,
2503 int capture_count,
2504 int subject_length);
2505
2506 void Apply(ReplacementStringBuilder* builder,
2507 int match_from,
2508 int match_to,
2509 Handle<JSArray> last_match_info);
2510
2511 // Number of distinct parts of the replacement pattern.
2512 int parts() {
2513 return parts_.length();
2514 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002515
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002516 bool simple_hint() {
2517 return simple_hint_;
2518 }
2519
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002520 private:
2521 enum PartType {
2522 SUBJECT_PREFIX = 1,
2523 SUBJECT_SUFFIX,
2524 SUBJECT_CAPTURE,
2525 REPLACEMENT_SUBSTRING,
2526 REPLACEMENT_STRING,
2527
2528 NUMBER_OF_PART_TYPES
2529 };
2530
2531 struct ReplacementPart {
2532 static inline ReplacementPart SubjectMatch() {
2533 return ReplacementPart(SUBJECT_CAPTURE, 0);
2534 }
2535 static inline ReplacementPart SubjectCapture(int capture_index) {
2536 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2537 }
2538 static inline ReplacementPart SubjectPrefix() {
2539 return ReplacementPart(SUBJECT_PREFIX, 0);
2540 }
2541 static inline ReplacementPart SubjectSuffix(int subject_length) {
2542 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2543 }
2544 static inline ReplacementPart ReplacementString() {
2545 return ReplacementPart(REPLACEMENT_STRING, 0);
2546 }
2547 static inline ReplacementPart ReplacementSubString(int from, int to) {
2548 ASSERT(from >= 0);
2549 ASSERT(to > from);
2550 return ReplacementPart(-from, to);
2551 }
2552
2553 // If tag <= 0 then it is the negation of a start index of a substring of
2554 // the replacement pattern, otherwise it's a value from PartType.
2555 ReplacementPart(int tag, int data)
2556 : tag(tag), data(data) {
2557 // Must be non-positive or a PartType value.
2558 ASSERT(tag < NUMBER_OF_PART_TYPES);
2559 }
2560 // Either a value of PartType or a non-positive number that is
2561 // the negation of an index into the replacement string.
2562 int tag;
2563 // The data value's interpretation depends on the value of tag:
2564 // tag == SUBJECT_PREFIX ||
2565 // tag == SUBJECT_SUFFIX: data is unused.
2566 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2567 // tag == REPLACEMENT_SUBSTRING ||
2568 // tag == REPLACEMENT_STRING: data is index into array of substrings
2569 // of the replacement string.
2570 // tag <= 0: Temporary representation of the substring of the replacement
2571 // string ranging over -tag .. data.
2572 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2573 // substring objects.
2574 int data;
2575 };
2576
2577 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002578 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002579 Vector<Char> characters,
2580 int capture_count,
2581 int subject_length) {
2582 int length = characters.length();
2583 int last = 0;
2584 for (int i = 0; i < length; i++) {
2585 Char c = characters[i];
2586 if (c == '$') {
2587 int next_index = i + 1;
2588 if (next_index == length) { // No next character!
2589 break;
2590 }
2591 Char c2 = characters[next_index];
2592 switch (c2) {
2593 case '$':
2594 if (i > last) {
2595 // There is a substring before. Include the first "$".
2596 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2597 last = next_index + 1; // Continue after the second "$".
2598 } else {
2599 // Let the next substring start with the second "$".
2600 last = next_index;
2601 }
2602 i = next_index;
2603 break;
2604 case '`':
2605 if (i > last) {
2606 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2607 }
2608 parts->Add(ReplacementPart::SubjectPrefix());
2609 i = next_index;
2610 last = i + 1;
2611 break;
2612 case '\'':
2613 if (i > last) {
2614 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2615 }
2616 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2617 i = next_index;
2618 last = i + 1;
2619 break;
2620 case '&':
2621 if (i > last) {
2622 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2623 }
2624 parts->Add(ReplacementPart::SubjectMatch());
2625 i = next_index;
2626 last = i + 1;
2627 break;
2628 case '0':
2629 case '1':
2630 case '2':
2631 case '3':
2632 case '4':
2633 case '5':
2634 case '6':
2635 case '7':
2636 case '8':
2637 case '9': {
2638 int capture_ref = c2 - '0';
2639 if (capture_ref > capture_count) {
2640 i = next_index;
2641 continue;
2642 }
2643 int second_digit_index = next_index + 1;
2644 if (second_digit_index < length) {
2645 // Peek ahead to see if we have two digits.
2646 Char c3 = characters[second_digit_index];
2647 if ('0' <= c3 && c3 <= '9') { // Double digits.
2648 int double_digit_ref = capture_ref * 10 + c3 - '0';
2649 if (double_digit_ref <= capture_count) {
2650 next_index = second_digit_index;
2651 capture_ref = double_digit_ref;
2652 }
2653 }
2654 }
2655 if (capture_ref > 0) {
2656 if (i > last) {
2657 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2658 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002659 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002660 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2661 last = next_index + 1;
2662 }
2663 i = next_index;
2664 break;
2665 }
2666 default:
2667 i = next_index;
2668 break;
2669 }
2670 }
2671 }
2672 if (length > last) {
2673 if (last == 0) {
2674 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002675 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002676 } else {
2677 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2678 }
2679 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002680 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002681 }
2682
2683 ZoneList<ReplacementPart> parts_;
2684 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002685 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002686};
2687
2688
2689void CompiledReplacement::Compile(Handle<String> replacement,
2690 int capture_count,
2691 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002692 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002693 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002694 String::FlatContent content = replacement->GetFlatContent();
2695 ASSERT(content.IsFlat());
2696 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002697 simple_hint_ = ParseReplacementPattern(&parts_,
2698 content.ToAsciiVector(),
2699 capture_count,
2700 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002701 } else {
2702 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002703 simple_hint_ = ParseReplacementPattern(&parts_,
2704 content.ToUC16Vector(),
2705 capture_count,
2706 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002707 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002708 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002709 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002710 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002711 int substring_index = 0;
2712 for (int i = 0, n = parts_.length(); i < n; i++) {
2713 int tag = parts_[i].tag;
2714 if (tag <= 0) { // A replacement string slice.
2715 int from = -tag;
2716 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002717 replacement_substrings_.Add(
2718 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002719 parts_[i].tag = REPLACEMENT_SUBSTRING;
2720 parts_[i].data = substring_index;
2721 substring_index++;
2722 } else if (tag == REPLACEMENT_STRING) {
2723 replacement_substrings_.Add(replacement);
2724 parts_[i].data = substring_index;
2725 substring_index++;
2726 }
2727 }
2728}
2729
2730
2731void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2732 int match_from,
2733 int match_to,
2734 Handle<JSArray> last_match_info) {
2735 for (int i = 0, n = parts_.length(); i < n; i++) {
2736 ReplacementPart part = parts_[i];
2737 switch (part.tag) {
2738 case SUBJECT_PREFIX:
2739 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2740 break;
2741 case SUBJECT_SUFFIX: {
2742 int subject_length = part.data;
2743 if (match_to < subject_length) {
2744 builder->AddSubjectSlice(match_to, subject_length);
2745 }
2746 break;
2747 }
2748 case SUBJECT_CAPTURE: {
2749 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002750 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002751 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2752 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2753 if (from >= 0 && to > from) {
2754 builder->AddSubjectSlice(from, to);
2755 }
2756 break;
2757 }
2758 case REPLACEMENT_SUBSTRING:
2759 case REPLACEMENT_STRING:
2760 builder->AddString(replacement_substrings_[part.data]);
2761 break;
2762 default:
2763 UNREACHABLE();
2764 }
2765 }
2766}
2767
2768
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002769void FindAsciiStringIndices(Vector<const char> subject,
2770 char pattern,
2771 ZoneList<int>* indices,
2772 unsigned int limit) {
2773 ASSERT(limit > 0);
2774 // Collect indices of pattern in subject using memchr.
2775 // Stop after finding at most limit values.
2776 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2777 const char* subject_end = subject_start + subject.length();
2778 const char* pos = subject_start;
2779 while (limit > 0) {
2780 pos = reinterpret_cast<const char*>(
2781 memchr(pos, pattern, subject_end - pos));
2782 if (pos == NULL) return;
2783 indices->Add(static_cast<int>(pos - subject_start));
2784 pos++;
2785 limit--;
2786 }
2787}
2788
2789
2790template <typename SubjectChar, typename PatternChar>
2791void FindStringIndices(Isolate* isolate,
2792 Vector<const SubjectChar> subject,
2793 Vector<const PatternChar> pattern,
2794 ZoneList<int>* indices,
2795 unsigned int limit) {
2796 ASSERT(limit > 0);
2797 // Collect indices of pattern in subject.
2798 // Stop after finding at most limit values.
2799 int pattern_length = pattern.length();
2800 int index = 0;
2801 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2802 while (limit > 0) {
2803 index = search.Search(subject, index);
2804 if (index < 0) return;
2805 indices->Add(index);
2806 index += pattern_length;
2807 limit--;
2808 }
2809}
2810
2811
2812void FindStringIndicesDispatch(Isolate* isolate,
2813 String* subject,
2814 String* pattern,
2815 ZoneList<int>* indices,
2816 unsigned int limit) {
2817 {
2818 AssertNoAllocation no_gc;
2819 String::FlatContent subject_content = subject->GetFlatContent();
2820 String::FlatContent pattern_content = pattern->GetFlatContent();
2821 ASSERT(subject_content.IsFlat());
2822 ASSERT(pattern_content.IsFlat());
2823 if (subject_content.IsAscii()) {
2824 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2825 if (pattern_content.IsAscii()) {
2826 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2827 if (pattern_vector.length() == 1) {
2828 FindAsciiStringIndices(subject_vector,
2829 pattern_vector[0],
2830 indices,
2831 limit);
2832 } else {
2833 FindStringIndices(isolate,
2834 subject_vector,
2835 pattern_vector,
2836 indices,
2837 limit);
2838 }
2839 } else {
2840 FindStringIndices(isolate,
2841 subject_vector,
2842 pattern_content.ToUC16Vector(),
2843 indices,
2844 limit);
2845 }
2846 } else {
2847 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002848 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002849 FindStringIndices(isolate,
2850 subject_vector,
2851 pattern_content.ToAsciiVector(),
2852 indices,
2853 limit);
2854 } else {
2855 FindStringIndices(isolate,
2856 subject_vector,
2857 pattern_content.ToUC16Vector(),
2858 indices,
2859 limit);
2860 }
2861 }
2862 }
2863}
2864
2865
2866template<typename ResultSeqString>
2867MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2868 Isolate* isolate,
2869 Handle<String> subject,
2870 Handle<JSRegExp> pattern_regexp,
2871 Handle<String> replacement) {
2872 ASSERT(subject->IsFlat());
2873 ASSERT(replacement->IsFlat());
2874
2875 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2876 ZoneList<int> indices(8);
2877 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2878 String* pattern =
2879 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2880 int subject_len = subject->length();
2881 int pattern_len = pattern->length();
2882 int replacement_len = replacement->length();
2883
2884 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2885
2886 int matches = indices.length();
2887 if (matches == 0) return *subject;
2888
2889 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2890 int subject_pos = 0;
2891 int result_pos = 0;
2892
2893 Handle<ResultSeqString> result;
2894 if (ResultSeqString::kHasAsciiEncoding) {
2895 result = Handle<ResultSeqString>::cast(
2896 isolate->factory()->NewRawAsciiString(result_len));
2897 } else {
2898 result = Handle<ResultSeqString>::cast(
2899 isolate->factory()->NewRawTwoByteString(result_len));
2900 }
2901
2902 for (int i = 0; i < matches; i++) {
2903 // Copy non-matched subject content.
2904 if (subject_pos < indices.at(i)) {
2905 String::WriteToFlat(*subject,
2906 result->GetChars() + result_pos,
2907 subject_pos,
2908 indices.at(i));
2909 result_pos += indices.at(i) - subject_pos;
2910 }
2911
2912 // Replace match.
2913 if (replacement_len > 0) {
2914 String::WriteToFlat(*replacement,
2915 result->GetChars() + result_pos,
2916 0,
2917 replacement_len);
2918 result_pos += replacement_len;
2919 }
2920
2921 subject_pos = indices.at(i) + pattern_len;
2922 }
2923 // Add remaining subject content at the end.
2924 if (subject_pos < subject_len) {
2925 String::WriteToFlat(*subject,
2926 result->GetChars() + result_pos,
2927 subject_pos,
2928 subject_len);
2929 }
2930 return *result;
2931}
2932
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002933
lrn@chromium.org303ada72010-10-27 09:33:13 +00002934MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002935 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002936 String* subject,
2937 JSRegExp* regexp,
2938 String* replacement,
2939 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002940 ASSERT(subject->IsFlat());
2941 ASSERT(replacement->IsFlat());
2942
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002943 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002944
2945 int length = subject->length();
2946 Handle<String> subject_handle(subject);
2947 Handle<JSRegExp> regexp_handle(regexp);
2948 Handle<String> replacement_handle(replacement);
2949 Handle<JSArray> last_match_info_handle(last_match_info);
2950 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2951 subject_handle,
2952 0,
2953 last_match_info_handle);
2954 if (match.is_null()) {
2955 return Failure::Exception();
2956 }
2957 if (match->IsNull()) {
2958 return *subject_handle;
2959 }
2960
2961 int capture_count = regexp_handle->CaptureCount();
2962
2963 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002964 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002965 CompiledReplacement compiled_replacement;
2966 compiled_replacement.Compile(replacement_handle,
2967 capture_count,
2968 length);
2969
2970 bool is_global = regexp_handle->GetFlags().is_global();
2971
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002972 // Shortcut for simple non-regexp global replacements
2973 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002974 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002975 compiled_replacement.simple_hint()) {
2976 if (subject_handle->HasOnlyAsciiChars() &&
2977 replacement_handle->HasOnlyAsciiChars()) {
2978 return StringReplaceStringWithString<SeqAsciiString>(
2979 isolate, subject_handle, regexp_handle, replacement_handle);
2980 } else {
2981 return StringReplaceStringWithString<SeqTwoByteString>(
2982 isolate, subject_handle, regexp_handle, replacement_handle);
2983 }
2984 }
2985
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002986 // Guessing the number of parts that the final result string is built
2987 // from. Global regexps can match any number of times, so we guess
2988 // conservatively.
2989 int expected_parts =
2990 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002991 ReplacementStringBuilder builder(isolate->heap(),
2992 subject_handle,
2993 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002994
2995 // Index of end of last match.
2996 int prev = 0;
2997
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002998 // Number of parts added by compiled replacement plus preceeding
2999 // string and possibly suffix after last match. It is possible for
3000 // all components to use two elements when encoded as two smis.
3001 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003002 bool matched = true;
3003 do {
3004 ASSERT(last_match_info_handle->HasFastElements());
3005 // Increase the capacity of the builder before entering local handle-scope,
3006 // so its internal buffer can safely allocate a new handle if it grows.
3007 builder.EnsureCapacity(parts_added_per_loop);
3008
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003009 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003010 int start, end;
3011 {
3012 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003013 FixedArray* match_info_array =
3014 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003015
3016 ASSERT_EQ(capture_count * 2 + 2,
3017 RegExpImpl::GetLastCaptureCount(match_info_array));
3018 start = RegExpImpl::GetCapture(match_info_array, 0);
3019 end = RegExpImpl::GetCapture(match_info_array, 1);
3020 }
3021
3022 if (prev < start) {
3023 builder.AddSubjectSlice(prev, start);
3024 }
3025 compiled_replacement.Apply(&builder,
3026 start,
3027 end,
3028 last_match_info_handle);
3029 prev = end;
3030
3031 // Only continue checking for global regexps.
3032 if (!is_global) break;
3033
3034 // Continue from where the match ended, unless it was an empty match.
3035 int next = end;
3036 if (start == end) {
3037 next = end + 1;
3038 if (next > length) break;
3039 }
3040
3041 match = RegExpImpl::Exec(regexp_handle,
3042 subject_handle,
3043 next,
3044 last_match_info_handle);
3045 if (match.is_null()) {
3046 return Failure::Exception();
3047 }
3048 matched = !match->IsNull();
3049 } while (matched);
3050
3051 if (prev < length) {
3052 builder.AddSubjectSlice(prev, length);
3053 }
3054
3055 return *(builder.ToString());
3056}
3057
3058
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003059template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003060MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003061 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003062 String* subject,
3063 JSRegExp* regexp,
3064 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003065 ASSERT(subject->IsFlat());
3066
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003067 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003068
3069 Handle<String> subject_handle(subject);
3070 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003071
3072 // Shortcut for simple non-regexp global replacements
3073 if (regexp_handle->GetFlags().is_global() &&
3074 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3075 Handle<String> empty_string_handle(HEAP->empty_string());
3076 if (subject_handle->HasOnlyAsciiChars()) {
3077 return StringReplaceStringWithString<SeqAsciiString>(
3078 isolate, subject_handle, regexp_handle, empty_string_handle);
3079 } else {
3080 return StringReplaceStringWithString<SeqTwoByteString>(
3081 isolate, subject_handle, regexp_handle, empty_string_handle);
3082 }
3083 }
3084
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003085 Handle<JSArray> last_match_info_handle(last_match_info);
3086 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3087 subject_handle,
3088 0,
3089 last_match_info_handle);
3090 if (match.is_null()) return Failure::Exception();
3091 if (match->IsNull()) return *subject_handle;
3092
3093 ASSERT(last_match_info_handle->HasFastElements());
3094
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003095 int start, end;
3096 {
3097 AssertNoAllocation match_info_array_is_not_in_a_handle;
3098 FixedArray* match_info_array =
3099 FixedArray::cast(last_match_info_handle->elements());
3100
3101 start = RegExpImpl::GetCapture(match_info_array, 0);
3102 end = RegExpImpl::GetCapture(match_info_array, 1);
3103 }
3104
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003105 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003106 int new_length = length - (end - start);
3107 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003108 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003109 }
3110 Handle<ResultSeqString> answer;
3111 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003112 answer = Handle<ResultSeqString>::cast(
3113 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003114 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003115 answer = Handle<ResultSeqString>::cast(
3116 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003117 }
3118
3119 // If the regexp isn't global, only match once.
3120 if (!regexp_handle->GetFlags().is_global()) {
3121 if (start > 0) {
3122 String::WriteToFlat(*subject_handle,
3123 answer->GetChars(),
3124 0,
3125 start);
3126 }
3127 if (end < length) {
3128 String::WriteToFlat(*subject_handle,
3129 answer->GetChars() + start,
3130 end,
3131 length);
3132 }
3133 return *answer;
3134 }
3135
3136 int prev = 0; // Index of end of last match.
3137 int next = 0; // Start of next search (prev unless last match was empty).
3138 int position = 0;
3139
3140 do {
3141 if (prev < start) {
3142 // Add substring subject[prev;start] to answer string.
3143 String::WriteToFlat(*subject_handle,
3144 answer->GetChars() + position,
3145 prev,
3146 start);
3147 position += start - prev;
3148 }
3149 prev = end;
3150 next = end;
3151 // Continue from where the match ended, unless it was an empty match.
3152 if (start == end) {
3153 next++;
3154 if (next > length) break;
3155 }
3156 match = RegExpImpl::Exec(regexp_handle,
3157 subject_handle,
3158 next,
3159 last_match_info_handle);
3160 if (match.is_null()) return Failure::Exception();
3161 if (match->IsNull()) break;
3162
3163 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003164 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003165 {
3166 AssertNoAllocation match_info_array_is_not_in_a_handle;
3167 FixedArray* match_info_array =
3168 FixedArray::cast(last_match_info_handle->elements());
3169 start = RegExpImpl::GetCapture(match_info_array, 0);
3170 end = RegExpImpl::GetCapture(match_info_array, 1);
3171 }
3172 } while (true);
3173
3174 if (prev < length) {
3175 // Add substring subject[prev;length] to answer string.
3176 String::WriteToFlat(*subject_handle,
3177 answer->GetChars() + position,
3178 prev,
3179 length);
3180 position += length - prev;
3181 }
3182
3183 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003184 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003185 }
3186
3187 // Shorten string and fill
3188 int string_size = ResultSeqString::SizeFor(position);
3189 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3190 int delta = allocated_string_size - string_size;
3191
3192 answer->set_length(position);
3193 if (delta == 0) return *answer;
3194
3195 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003196 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003197 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3198 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3199 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003200
3201 return *answer;
3202}
3203
3204
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003205RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003206 ASSERT(args.length() == 4);
3207
3208 CONVERT_CHECKED(String, subject, args[0]);
3209 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003210 Object* flat_subject;
3211 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3212 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3213 return maybe_flat_subject;
3214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003215 }
3216 subject = String::cast(flat_subject);
3217 }
3218
3219 CONVERT_CHECKED(String, replacement, args[2]);
3220 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003221 Object* flat_replacement;
3222 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3223 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3224 return maybe_flat_replacement;
3225 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003226 }
3227 replacement = String::cast(flat_replacement);
3228 }
3229
3230 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3231 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3232
3233 ASSERT(last_match_info->HasFastElements());
3234
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003235 if (replacement->length() == 0) {
3236 if (subject->HasOnlyAsciiChars()) {
3237 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003238 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003239 } else {
3240 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003241 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003242 }
3243 }
3244
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245 return StringReplaceRegExpWithString(isolate,
3246 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003247 regexp,
3248 replacement,
3249 last_match_info);
3250}
3251
3252
ager@chromium.org7c537e22008-10-16 08:43:32 +00003253// Perform string match of pattern on subject, starting at start index.
3254// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003255// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003256int Runtime::StringMatch(Isolate* isolate,
3257 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003258 Handle<String> pat,
3259 int start_index) {
3260 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003261 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003262
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003263 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003264 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003265
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003266 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003267 if (start_index + pattern_length > subject_length) return -1;
3268
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003269 if (!sub->IsFlat()) FlattenString(sub);
3270 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003271
ager@chromium.org7c537e22008-10-16 08:43:32 +00003272 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003273 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003274 String::FlatContent seq_sub = sub->GetFlatContent();
3275 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003276
ager@chromium.org7c537e22008-10-16 08:43:32 +00003277 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003278 if (seq_pat.IsAscii()) {
3279 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3280 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003281 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003282 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003283 pat_vector,
3284 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003285 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003286 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003287 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003288 pat_vector,
3289 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003290 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003291 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3292 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003293 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003294 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003295 pat_vector,
3296 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003297 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003298 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003299 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003300 pat_vector,
3301 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003302}
3303
3304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003305RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003306 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003307 ASSERT(args.length() == 3);
3308
ager@chromium.org7c537e22008-10-16 08:43:32 +00003309 CONVERT_ARG_CHECKED(String, sub, 0);
3310 CONVERT_ARG_CHECKED(String, pat, 1);
3311
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003312 Object* index = args[2];
3313 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003314 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003315
ager@chromium.org870a0b62008-11-04 11:43:05 +00003316 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003317 int position =
3318 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003319 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003320}
3321
3322
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003323template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003324static int StringMatchBackwards(Vector<const schar> subject,
3325 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003326 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003327 int pattern_length = pattern.length();
3328 ASSERT(pattern_length >= 1);
3329 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003330
3331 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003332 for (int i = 0; i < pattern_length; i++) {
3333 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003334 if (c > String::kMaxAsciiCharCode) {
3335 return -1;
3336 }
3337 }
3338 }
3339
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003340 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003341 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003342 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003343 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003344 while (j < pattern_length) {
3345 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003346 break;
3347 }
3348 j++;
3349 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003350 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003351 return i;
3352 }
3353 }
3354 return -1;
3355}
3356
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003357RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003358 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003359 ASSERT(args.length() == 3);
3360
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003361 CONVERT_ARG_CHECKED(String, sub, 0);
3362 CONVERT_ARG_CHECKED(String, pat, 1);
3363
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003364 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003365 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003366 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003367
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003368 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003369 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003371 if (start_index + pat_length > sub_length) {
3372 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003373 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003374
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003375 if (pat_length == 0) {
3376 return Smi::FromInt(start_index);
3377 }
3378
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003379 if (!sub->IsFlat()) FlattenString(sub);
3380 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003381
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003382 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003383 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3384
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003385 String::FlatContent sub_content = sub->GetFlatContent();
3386 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003387
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003388 if (pat_content.IsAscii()) {
3389 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3390 if (sub_content.IsAscii()) {
3391 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003392 pat_vector,
3393 start_index);
3394 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003395 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003396 pat_vector,
3397 start_index);
3398 }
3399 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003400 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3401 if (sub_content.IsAscii()) {
3402 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003403 pat_vector,
3404 start_index);
3405 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003406 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003407 pat_vector,
3408 start_index);
3409 }
3410 }
3411
3412 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003413}
3414
3415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003416RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417 NoHandleAllocation ha;
3418 ASSERT(args.length() == 2);
3419
3420 CONVERT_CHECKED(String, str1, args[0]);
3421 CONVERT_CHECKED(String, str2, args[1]);
3422
3423 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003424 int str1_length = str1->length();
3425 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003426
3427 // Decide trivial cases without flattening.
3428 if (str1_length == 0) {
3429 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3430 return Smi::FromInt(-str2_length);
3431 } else {
3432 if (str2_length == 0) return Smi::FromInt(str1_length);
3433 }
3434
3435 int end = str1_length < str2_length ? str1_length : str2_length;
3436
3437 // No need to flatten if we are going to find the answer on the first
3438 // character. At this point we know there is at least one character
3439 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003440 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003441 if (d != 0) return Smi::FromInt(d);
3442
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003443 str1->TryFlatten();
3444 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003446 StringInputBuffer& buf1 =
3447 *isolate->runtime_state()->string_locale_compare_buf1();
3448 StringInputBuffer& buf2 =
3449 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003450
3451 buf1.Reset(str1);
3452 buf2.Reset(str2);
3453
3454 for (int i = 0; i < end; i++) {
3455 uint16_t char1 = buf1.GetNext();
3456 uint16_t char2 = buf2.GetNext();
3457 if (char1 != char2) return Smi::FromInt(char1 - char2);
3458 }
3459
3460 return Smi::FromInt(str1_length - str2_length);
3461}
3462
3463
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003464RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003465 NoHandleAllocation ha;
3466 ASSERT(args.length() == 3);
3467
3468 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003469 int start, end;
3470 // We have a fast integer-only case here to avoid a conversion to double in
3471 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003472 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3473 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3474 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3475 start = from_number;
3476 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003477 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003478 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3479 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003480 start = FastD2I(from_number);
3481 end = FastD2I(to_number);
3482 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003483 RUNTIME_ASSERT(end >= start);
3484 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003485 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003486 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003487 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488}
3489
3490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003491RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003492 ASSERT_EQ(3, args.length());
3493
3494 CONVERT_ARG_CHECKED(String, subject, 0);
3495 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3496 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3497 HandleScope handles;
3498
3499 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3500
3501 if (match.is_null()) {
3502 return Failure::Exception();
3503 }
3504 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003505 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003506 }
3507 int length = subject->length();
3508
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003509 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003510 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003511 int start;
3512 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003513 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003514 {
3515 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003516 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003517 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3518 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3519 }
3520 offsets.Add(start);
3521 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003522 if (start == end) if (++end > length) break;
3523 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003524 if (match.is_null()) {
3525 return Failure::Exception();
3526 }
3527 } while (!match->IsNull());
3528 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003529 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003530 Handle<String> substring = isolate->factory()->
3531 NewSubString(subject, offsets.at(0), offsets.at(1));
3532 elements->set(0, *substring);
3533 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003534 int from = offsets.at(i * 2);
3535 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003536 Handle<String> substring = isolate->factory()->
3537 NewProperSubString(subject, from, to);
3538 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003539 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003540 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003541 result->set_length(Smi::FromInt(matches));
3542 return *result;
3543}
3544
3545
lrn@chromium.org25156de2010-04-06 13:10:27 +00003546// Two smis before and after the match, for very long strings.
3547const int kMaxBuilderEntriesPerRegExpMatch = 5;
3548
3549
3550static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3551 Handle<JSArray> last_match_info,
3552 int match_start,
3553 int match_end) {
3554 // Fill last_match_info with a single capture.
3555 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3556 AssertNoAllocation no_gc;
3557 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3558 RegExpImpl::SetLastCaptureCount(elements, 2);
3559 RegExpImpl::SetLastInput(elements, *subject);
3560 RegExpImpl::SetLastSubject(elements, *subject);
3561 RegExpImpl::SetCapture(elements, 0, match_start);
3562 RegExpImpl::SetCapture(elements, 1, match_end);
3563}
3564
3565
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003566template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003567static bool SearchStringMultiple(Isolate* isolate,
3568 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003569 Vector<const PatternChar> pattern,
3570 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003571 FixedArrayBuilder* builder,
3572 int* match_pos) {
3573 int pos = *match_pos;
3574 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003575 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003576 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003577 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003578 while (pos <= max_search_start) {
3579 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3580 *match_pos = pos;
3581 return false;
3582 }
3583 // Position of end of previous match.
3584 int match_end = pos + pattern_length;
3585 int new_pos = search.Search(subject, match_end);
3586 if (new_pos >= 0) {
3587 // A match.
3588 if (new_pos > match_end) {
3589 ReplacementStringBuilder::AddSubjectSlice(builder,
3590 match_end,
3591 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003592 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003593 pos = new_pos;
3594 builder->Add(pattern_string);
3595 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003596 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003597 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003598 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003599
lrn@chromium.org25156de2010-04-06 13:10:27 +00003600 if (pos < max_search_start) {
3601 ReplacementStringBuilder::AddSubjectSlice(builder,
3602 pos + pattern_length,
3603 subject_length);
3604 }
3605 *match_pos = pos;
3606 return true;
3607}
3608
3609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003610static bool SearchStringMultiple(Isolate* isolate,
3611 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003612 Handle<String> pattern,
3613 Handle<JSArray> last_match_info,
3614 FixedArrayBuilder* builder) {
3615 ASSERT(subject->IsFlat());
3616 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003617
3618 // Treating as if a previous match was before first character.
3619 int match_pos = -pattern->length();
3620
3621 for (;;) { // Break when search complete.
3622 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3623 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003624 String::FlatContent subject_content = subject->GetFlatContent();
3625 String::FlatContent pattern_content = pattern->GetFlatContent();
3626 if (subject_content.IsAscii()) {
3627 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3628 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003629 if (SearchStringMultiple(isolate,
3630 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003631 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003632 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003633 builder,
3634 &match_pos)) break;
3635 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003636 if (SearchStringMultiple(isolate,
3637 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003638 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003639 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003640 builder,
3641 &match_pos)) break;
3642 }
3643 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003644 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3645 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646 if (SearchStringMultiple(isolate,
3647 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003648 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003649 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003650 builder,
3651 &match_pos)) break;
3652 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003653 if (SearchStringMultiple(isolate,
3654 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003655 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003656 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003657 builder,
3658 &match_pos)) break;
3659 }
3660 }
3661 }
3662
3663 if (match_pos >= 0) {
3664 SetLastMatchInfoNoCaptures(subject,
3665 last_match_info,
3666 match_pos,
3667 match_pos + pattern->length());
3668 return true;
3669 }
3670 return false; // No matches at all.
3671}
3672
3673
3674static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003675 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003676 Handle<String> subject,
3677 Handle<JSRegExp> regexp,
3678 Handle<JSArray> last_match_array,
3679 FixedArrayBuilder* builder) {
3680 ASSERT(subject->IsFlat());
3681 int match_start = -1;
3682 int match_end = 0;
3683 int pos = 0;
3684 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3685 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3686
3687 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003688 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003689 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003690 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003691
3692 for (;;) { // Break on failure, return on exception.
3693 RegExpImpl::IrregexpResult result =
3694 RegExpImpl::IrregexpExecOnce(regexp,
3695 subject,
3696 pos,
3697 register_vector);
3698 if (result == RegExpImpl::RE_SUCCESS) {
3699 match_start = register_vector[0];
3700 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3701 if (match_end < match_start) {
3702 ReplacementStringBuilder::AddSubjectSlice(builder,
3703 match_end,
3704 match_start);
3705 }
3706 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003707 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003708 if (!first) {
3709 builder->Add(*isolate->factory()->NewProperSubString(subject,
3710 match_start,
3711 match_end));
3712 } else {
3713 builder->Add(*isolate->factory()->NewSubString(subject,
3714 match_start,
3715 match_end));
3716 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003717 if (match_start != match_end) {
3718 pos = match_end;
3719 } else {
3720 pos = match_end + 1;
3721 if (pos > subject_length) break;
3722 }
3723 } else if (result == RegExpImpl::RE_FAILURE) {
3724 break;
3725 } else {
3726 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3727 return result;
3728 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003729 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003730 }
3731
3732 if (match_start >= 0) {
3733 if (match_end < subject_length) {
3734 ReplacementStringBuilder::AddSubjectSlice(builder,
3735 match_end,
3736 subject_length);
3737 }
3738 SetLastMatchInfoNoCaptures(subject,
3739 last_match_array,
3740 match_start,
3741 match_end);
3742 return RegExpImpl::RE_SUCCESS;
3743 } else {
3744 return RegExpImpl::RE_FAILURE; // No matches at all.
3745 }
3746}
3747
3748
3749static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003750 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003751 Handle<String> subject,
3752 Handle<JSRegExp> regexp,
3753 Handle<JSArray> last_match_array,
3754 FixedArrayBuilder* builder) {
3755
3756 ASSERT(subject->IsFlat());
3757 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3758 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3759
3760 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003761 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003762
3763 RegExpImpl::IrregexpResult result =
3764 RegExpImpl::IrregexpExecOnce(regexp,
3765 subject,
3766 0,
3767 register_vector);
3768
3769 int capture_count = regexp->CaptureCount();
3770 int subject_length = subject->length();
3771
3772 // Position to search from.
3773 int pos = 0;
3774 // End of previous match. Differs from pos if match was empty.
3775 int match_end = 0;
3776 if (result == RegExpImpl::RE_SUCCESS) {
3777 // Need to keep a copy of the previous match for creating last_match_info
3778 // at the end, so we have two vectors that we swap between.
3779 OffsetsVector registers2(required_registers);
3780 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003781 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003782 do {
3783 int match_start = register_vector[0];
3784 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3785 if (match_end < match_start) {
3786 ReplacementStringBuilder::AddSubjectSlice(builder,
3787 match_end,
3788 match_start);
3789 }
3790 match_end = register_vector[1];
3791
3792 {
3793 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003795 // Arguments array to replace function is match, captures, index and
3796 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003797 Handle<FixedArray> elements =
3798 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003799 Handle<String> match;
3800 if (!first) {
3801 match = isolate->factory()->NewProperSubString(subject,
3802 match_start,
3803 match_end);
3804 } else {
3805 match = isolate->factory()->NewSubString(subject,
3806 match_start,
3807 match_end);
3808 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003809 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003810 for (int i = 1; i <= capture_count; i++) {
3811 int start = register_vector[i * 2];
3812 if (start >= 0) {
3813 int end = register_vector[i * 2 + 1];
3814 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003815 Handle<String> substring;
3816 if (!first) {
3817 substring = isolate->factory()->NewProperSubString(subject,
3818 start,
3819 end);
3820 } else {
3821 substring = isolate->factory()->NewSubString(subject, start, end);
3822 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003823 elements->set(i, *substring);
3824 } else {
3825 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003826 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003827 }
3828 }
3829 elements->set(capture_count + 1, Smi::FromInt(match_start));
3830 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003831 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003832 }
3833 // Swap register vectors, so the last successful match is in
3834 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003835 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003836 prev_register_vector = register_vector;
3837 register_vector = tmp;
3838
3839 if (match_end > match_start) {
3840 pos = match_end;
3841 } else {
3842 pos = match_end + 1;
3843 if (pos > subject_length) {
3844 break;
3845 }
3846 }
3847
3848 result = RegExpImpl::IrregexpExecOnce(regexp,
3849 subject,
3850 pos,
3851 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003852 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003853 } while (result == RegExpImpl::RE_SUCCESS);
3854
3855 if (result != RegExpImpl::RE_EXCEPTION) {
3856 // Finished matching, with at least one match.
3857 if (match_end < subject_length) {
3858 ReplacementStringBuilder::AddSubjectSlice(builder,
3859 match_end,
3860 subject_length);
3861 }
3862
3863 int last_match_capture_count = (capture_count + 1) * 2;
3864 int last_match_array_size =
3865 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3866 last_match_array->EnsureSize(last_match_array_size);
3867 AssertNoAllocation no_gc;
3868 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3869 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3870 RegExpImpl::SetLastSubject(elements, *subject);
3871 RegExpImpl::SetLastInput(elements, *subject);
3872 for (int i = 0; i < last_match_capture_count; i++) {
3873 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3874 }
3875 return RegExpImpl::RE_SUCCESS;
3876 }
3877 }
3878 // No matches at all, return failure or exception result directly.
3879 return result;
3880}
3881
3882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003883RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003884 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003885 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003886
3887 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003888 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003889 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3890 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3891 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3892
3893 ASSERT(last_match_info->HasFastElements());
3894 ASSERT(regexp->GetFlags().is_global());
3895 Handle<FixedArray> result_elements;
3896 if (result_array->HasFastElements()) {
3897 result_elements =
3898 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003899 }
3900 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003901 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003902 }
3903 FixedArrayBuilder builder(result_elements);
3904
3905 if (regexp->TypeTag() == JSRegExp::ATOM) {
3906 Handle<String> pattern(
3907 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003908 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003909 if (SearchStringMultiple(isolate, subject, pattern,
3910 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003911 return *builder.ToJSArray(result_array);
3912 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003913 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003914 }
3915
3916 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3917
3918 RegExpImpl::IrregexpResult result;
3919 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003920 result = SearchRegExpNoCaptureMultiple(isolate,
3921 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003922 regexp,
3923 last_match_info,
3924 &builder);
3925 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003926 result = SearchRegExpMultiple(isolate,
3927 subject,
3928 regexp,
3929 last_match_info,
3930 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003931 }
3932 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003933 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003934 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3935 return Failure::Exception();
3936}
3937
3938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003939RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003940 NoHandleAllocation ha;
3941 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003942 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003943 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003944
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003945 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003946 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003947 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003948 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003949 // Character array used for conversion.
3950 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003951 return isolate->heap()->
3952 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003953 }
3954 }
3955
3956 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003957 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003959 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003960 }
3961 if (isinf(value)) {
3962 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003963 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003964 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003965 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003966 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003968 MaybeObject* result =
3969 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 DeleteArray(str);
3971 return result;
3972}
3973
3974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003975RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003976 NoHandleAllocation ha;
3977 ASSERT(args.length() == 2);
3978
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003979 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003980 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003981 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003982 }
3983 if (isinf(value)) {
3984 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003985 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003987 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003989 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 int f = FastD2I(f_number);
3991 RUNTIME_ASSERT(f >= 0);
3992 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003993 MaybeObject* res =
3994 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003997}
3998
3999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004000RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001 NoHandleAllocation ha;
4002 ASSERT(args.length() == 2);
4003
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004004 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004005 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004006 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004007 }
4008 if (isinf(value)) {
4009 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004010 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004012 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004013 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004014 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 int f = FastD2I(f_number);
4016 RUNTIME_ASSERT(f >= -1 && f <= 20);
4017 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004018 MaybeObject* res =
4019 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004021 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022}
4023
4024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004025RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026 NoHandleAllocation ha;
4027 ASSERT(args.length() == 2);
4028
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004029 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004031 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 }
4033 if (isinf(value)) {
4034 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004035 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004037 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004039 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040 int f = FastD2I(f_number);
4041 RUNTIME_ASSERT(f >= 1 && f <= 21);
4042 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004043 MaybeObject* res =
4044 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004046 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047}
4048
4049
4050// Returns a single character string where first character equals
4051// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004052static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004053 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004054 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004055 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004056 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004058 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059}
4060
4061
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004062MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4063 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004064 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 // Handle [] indexing on Strings
4066 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004067 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4068 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 }
4070
4071 // Handle [] indexing on String objects
4072 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004073 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4074 Handle<Object> result =
4075 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4076 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 }
4078
4079 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004080 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 return prototype->GetElement(index);
4082 }
4083
4084 return object->GetElement(index);
4085}
4086
4087
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004088MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4089 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004090 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004091 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004092
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004094 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004095 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004096 isolate->factory()->NewTypeError("non_object_property_load",
4097 HandleVector(args, 2));
4098 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 }
4100
4101 // Check if the given key is an array index.
4102 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004103 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004104 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 }
4106
4107 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004108 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004110 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 bool has_pending_exception = false;
4113 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004114 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004116 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 }
4118
ager@chromium.org32912102009-01-16 10:38:43 +00004119 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120 // the element if so.
4121 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004122 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004124 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125 }
4126}
4127
4128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004129RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130 NoHandleAllocation ha;
4131 ASSERT(args.length() == 2);
4132
4133 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004134 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004136 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004137}
4138
4139
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004140MaybeObject* TransitionElements(Handle<Object> object,
4141 ElementsKind to_kind,
4142 Isolate* isolate) {
4143 HandleScope scope(isolate);
4144 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4145 ElementsKind from_kind =
4146 Handle<JSObject>::cast(object)->map()->elements_kind();
4147 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
4148 Handle<Object> result =
4149 TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
4150 if (result.is_null()) return isolate->ThrowIllegalOperation();
4151 return *result;
4152 }
4153 return isolate->ThrowIllegalOperation();
4154}
4155
4156
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004157// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004158RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004159 NoHandleAllocation ha;
4160 ASSERT(args.length() == 2);
4161
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004162 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004163 // itself.
4164 //
4165 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004166 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004167 // global proxy object never has properties. This is the case
4168 // because the global proxy object forwards everything to its hidden
4169 // prototype including local lookups.
4170 //
4171 // Additionally, we need to make sure that we do not cache results
4172 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004173 if (args[0]->IsJSObject()) {
4174 if (!args[0]->IsJSGlobalProxy() &&
4175 !args[0]->IsAccessCheckNeeded() &&
4176 args[1]->IsString()) {
4177 JSObject* receiver = JSObject::cast(args[0]);
4178 String* key = String::cast(args[1]);
4179 if (receiver->HasFastProperties()) {
4180 // Attempt to use lookup cache.
4181 Map* receiver_map = receiver->map();
4182 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4183 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4184 if (offset != -1) {
4185 Object* value = receiver->FastPropertyAt(offset);
4186 return value->IsTheHole()
4187 ? isolate->heap()->undefined_value()
4188 : value;
4189 }
4190 // Lookup cache miss. Perform lookup and update the cache if
4191 // appropriate.
4192 LookupResult result(isolate);
4193 receiver->LocalLookup(key, &result);
4194 if (result.IsProperty() && result.type() == FIELD) {
4195 int offset = result.GetFieldIndex();
4196 keyed_lookup_cache->Update(receiver_map, key, offset);
4197 return receiver->FastPropertyAt(offset);
4198 }
4199 } else {
4200 // Attempt dictionary lookup.
4201 StringDictionary* dictionary = receiver->property_dictionary();
4202 int entry = dictionary->FindEntry(key);
4203 if ((entry != StringDictionary::kNotFound) &&
4204 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4205 Object* value = dictionary->ValueAt(entry);
4206 if (!receiver->IsGlobalObject()) return value;
4207 value = JSGlobalPropertyCell::cast(value)->value();
4208 if (!value->IsTheHole()) return value;
4209 // If value is the hole do the general lookup.
4210 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004211 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004212 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4213 // JSObject without a string key. If the key is a Smi, check for a
4214 // definite out-of-bounds access to elements, which is a strong indicator
4215 // that subsequent accesses will also call the runtime. Proactively
4216 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4217 // doubles for those future calls in the case that the elements would
4218 // become FAST_DOUBLE_ELEMENTS.
4219 Handle<JSObject> js_object(args.at<JSObject>(0));
4220 ElementsKind elements_kind = js_object->GetElementsKind();
4221 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4222 elements_kind == FAST_DOUBLE_ELEMENTS) {
4223 FixedArrayBase* elements = js_object->elements();
4224 if (args.at<Smi>(1)->value() >= elements->length()) {
4225 MaybeObject* maybe_object = TransitionElements(js_object,
4226 FAST_ELEMENTS,
4227 isolate);
4228 if (maybe_object->IsFailure()) return maybe_object;
4229 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004230 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004231 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004232 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4233 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004234 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004235 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004236 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004237 if (index >= 0 && index < str->length()) {
4238 Handle<Object> result = GetCharAt(str, index);
4239 return *result;
4240 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004241 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004242
4243 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004244 return Runtime::GetObjectProperty(isolate,
4245 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004246 args.at<Object>(1));
4247}
4248
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004249// Implements part of 8.12.9 DefineOwnProperty.
4250// There are 3 cases that lead here:
4251// Step 4b - define a new accessor property.
4252// Steps 9c & 12 - replace an existing data property with an accessor property.
4253// Step 12 - update an existing accessor property with an accessor or generic
4254// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004255RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004256 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004257 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004258 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4259 CONVERT_CHECKED(String, name, args[1]);
4260 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004261 Object* fun = args[3];
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004262 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004263 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4264 int unchecked = flag_attr->value();
4265 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4266 RUNTIME_ASSERT(!obj->IsNull());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004267 LookupResult result(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004268 obj->LocalLookupRealNamedProperty(name, &result);
4269
4270 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4271 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4272 // delete it to avoid running into trouble in DefineAccessor, which
4273 // handles this incorrectly if the property is readonly (does nothing)
4274 if (result.IsProperty() &&
4275 (result.type() == FIELD || result.type() == NORMAL
4276 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004277 Object* ok;
4278 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004279 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004280 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4281 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004282 }
4283 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4284}
4285
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004286// Implements part of 8.12.9 DefineOwnProperty.
4287// There are 3 cases that lead here:
4288// Step 4a - define a new data property.
4289// Steps 9b & 12 - replace an existing accessor property with a data property.
4290// Step 12 - update an existing data property with a data or generic
4291// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004292RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004293 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004294 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004295 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4296 CONVERT_ARG_CHECKED(String, name, 1);
4297 Handle<Object> obj_value = args.at<Object>(2);
4298
4299 CONVERT_CHECKED(Smi, flag, args[3]);
4300 int unchecked = flag->value();
4301 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4302
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004303 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4304
4305 // Check if this is an element.
4306 uint32_t index;
4307 bool is_element = name->AsArrayIndex(&index);
4308
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004309 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004310 // If elements are in fast case we always implicitly assume that:
4311 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004312 if (is_element && (attr != NONE ||
4313 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004314 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004315 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004316 // We do not need to do access checks here since these has already
4317 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004318 Handle<Object> proto(js_object->GetPrototype());
4319 // If proxy is detached, ignore the assignment. Alternatively,
4320 // we could throw an exception.
4321 if (proto->IsNull()) return *obj_value;
4322 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004323 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004324
4325 // Don't allow element properties to be redefined on objects with external
4326 // array elements.
4327 if (js_object->HasExternalArrayElements()) {
4328 Handle<Object> args[2] = { js_object, name };
4329 Handle<Object> error =
4330 isolate->factory()->NewTypeError("redef_external_array_element",
4331 HandleVector(args, 2));
4332 return isolate->Throw(*error);
4333 }
4334
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004335 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004336 // Make sure that we never go back to fast case.
4337 dictionary->set_requires_slow_elements();
4338 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004339 Handle<NumberDictionary> extended_dictionary =
4340 NumberDictionarySet(dictionary, index, obj_value, details);
4341 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004342 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004343 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4344 } else {
4345 js_object->set_elements(*extended_dictionary);
4346 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004347 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004348 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004349 }
4350
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004351 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004352 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004353
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004354 // To be compatible with safari we do not change the value on API objects
4355 // in defineProperty. Firefox disagrees here, and actually changes the value.
4356 if (result.IsProperty() &&
4357 (result.type() == CALLBACKS) &&
4358 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004359 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004360 }
4361
ager@chromium.org5c838252010-02-19 08:53:10 +00004362 // Take special care when attributes are different and there is already
4363 // a property. For simplicity we normalize the property which enables us
4364 // to not worry about changing the instance_descriptor and creating a new
4365 // map. The current version of SetObjectProperty does not handle attributes
4366 // correctly in the case where a property is a field and is reset with
4367 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004368 if (result.IsProperty() &&
4369 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004370 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004371 if (js_object->IsJSGlobalProxy()) {
4372 // Since the result is a property, the prototype will exist so
4373 // we don't have to check for null.
4374 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004375 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004376 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004377 // Use IgnoreAttributes version since a readonly property may be
4378 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004379 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4380 *obj_value,
4381 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004382 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004383
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004384 return Runtime::ForceSetObjectProperty(isolate,
4385 js_object,
4386 name,
4387 obj_value,
4388 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004389}
4390
4391
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004392// Special case for elements if any of the flags are true.
4393// If elements are in fast case we always implicitly assume that:
4394// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4395static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4396 Handle<JSObject> js_object,
4397 uint32_t index,
4398 Handle<Object> value,
4399 PropertyAttributes attr) {
4400 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004401 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004402 // Make sure that we never go back to fast case.
4403 dictionary->set_requires_slow_elements();
4404 PropertyDetails details = PropertyDetails(attr, NORMAL);
4405 Handle<NumberDictionary> extended_dictionary =
4406 NumberDictionarySet(dictionary, index, value, details);
4407 if (*extended_dictionary != *dictionary) {
4408 js_object->set_elements(*extended_dictionary);
4409 }
4410 return *value;
4411}
4412
4413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004414MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4415 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004416 Handle<Object> key,
4417 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004418 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004419 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004420 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004421
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004423 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004424 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 isolate->factory()->NewTypeError("non_object_property_store",
4426 HandleVector(args, 2));
4427 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004428 }
4429
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004430 if (object->IsJSProxy()) {
4431 bool has_pending_exception = false;
4432 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4433 if (has_pending_exception) return Failure::Exception();
4434 return JSProxy::cast(*object)->SetProperty(
4435 String::cast(*name), *value, attr, strict_mode);
4436 }
4437
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 // If the object isn't a JavaScript object, we ignore the store.
4439 if (!object->IsJSObject()) return *value;
4440
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004441 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4442
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004443 // Check if the given key is an array index.
4444 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004445 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004446 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4447 // of a string using [] notation. We need to support this too in
4448 // JavaScript.
4449 // In the case of a String object we just need to redirect the assignment to
4450 // the underlying string if the index is in range. Since the underlying
4451 // string does nothing with the assignment then we can ignore such
4452 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004453 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004454 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004455 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004456
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004457 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4458 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4459 }
4460
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004461 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004462 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 return *value;
4464 }
4465
4466 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004467 Handle<Object> result;
4468 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004469 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4470 return NormalizeObjectSetElement(isolate,
4471 js_object,
4472 index,
4473 value,
4474 attr);
4475 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004476 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004478 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004479 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004480 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004482 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 return *value;
4484 }
4485
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004486 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004487 bool has_pending_exception = false;
4488 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4489 if (has_pending_exception) return Failure::Exception();
4490 Handle<String> name = Handle<String>::cast(converted);
4491
4492 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004493 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004494 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004495 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004496 }
4497}
4498
4499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004500MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4501 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004502 Handle<Object> key,
4503 Handle<Object> value,
4504 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004505 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004506
4507 // Check if the given key is an array index.
4508 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004509 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004510 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4511 // of a string using [] notation. We need to support this too in
4512 // JavaScript.
4513 // In the case of a String object we just need to redirect the assignment to
4514 // the underlying string if the index is in range. Since the underlying
4515 // string does nothing with the assignment then we can ignore such
4516 // assignments.
4517 if (js_object->IsStringObjectWithCharacterAt(index)) {
4518 return *value;
4519 }
4520
whesse@chromium.org7b260152011-06-20 15:33:18 +00004521 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004522 }
4523
4524 if (key->IsString()) {
4525 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004526 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004527 } else {
4528 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004529 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004530 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4531 *value,
4532 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004533 }
4534 }
4535
4536 // Call-back into JavaScript to convert the key to a string.
4537 bool has_pending_exception = false;
4538 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4539 if (has_pending_exception) return Failure::Exception();
4540 Handle<String> name = Handle<String>::cast(converted);
4541
4542 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004543 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004544 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004545 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004546 }
4547}
4548
4549
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004550MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004551 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004552 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004553 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004554
4555 // Check if the given key is an array index.
4556 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004557 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004558 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4559 // characters of a string using [] notation. In the case of a
4560 // String object we just need to redirect the deletion to the
4561 // underlying string if the index is in range. Since the
4562 // underlying string does nothing with the deletion, we can ignore
4563 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004564 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004565 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004566 }
4567
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004568 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004569 }
4570
4571 Handle<String> key_string;
4572 if (key->IsString()) {
4573 key_string = Handle<String>::cast(key);
4574 } else {
4575 // Call-back into JavaScript to convert the key to a string.
4576 bool has_pending_exception = false;
4577 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4578 if (has_pending_exception) return Failure::Exception();
4579 key_string = Handle<String>::cast(converted);
4580 }
4581
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004582 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004583 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004584}
4585
4586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004587RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004589 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004590
4591 Handle<Object> object = args.at<Object>(0);
4592 Handle<Object> key = args.at<Object>(1);
4593 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004594 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004595 RUNTIME_ASSERT(
4596 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004597 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004598 PropertyAttributes attributes =
4599 static_cast<PropertyAttributes>(unchecked_attributes);
4600
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004601 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004602 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004603 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4604 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004606
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004607 return Runtime::SetObjectProperty(isolate,
4608 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004609 key,
4610 value,
4611 attributes,
4612 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004613}
4614
4615
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004616RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4617 NoHandleAllocation ha;
4618 RUNTIME_ASSERT(args.length() == 1);
4619 Handle<Object> object = args.at<Object>(0);
4620 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4621}
4622
4623
4624RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4625 NoHandleAllocation ha;
4626 RUNTIME_ASSERT(args.length() == 1);
4627 Handle<Object> object = args.at<Object>(0);
4628 return TransitionElements(object, FAST_ELEMENTS, isolate);
4629}
4630
4631
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004632// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004633// This is used to decide if we should transform null and undefined
4634// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004635RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004636 NoHandleAllocation ha;
4637 RUNTIME_ASSERT(args.length() == 1);
4638
4639 Handle<Object> object = args.at<Object>(0);
4640
4641 if (object->IsJSFunction()) {
4642 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004643 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004644 }
4645 return isolate->heap()->undefined_value();
4646}
4647
4648
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004649RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4650 RUNTIME_ASSERT(args.length() == 5);
4651 CONVERT_ARG_CHECKED(JSObject, object, 0);
4652 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4653 Handle<Object> value = args.at<Object>(2);
4654 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4655 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4656 HandleScope scope;
4657
4658 Object* raw_boilerplate_object = literals->get(literal_index);
4659 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4660#if DEBUG
4661 ElementsKind elements_kind = object->GetElementsKind();
4662#endif
4663 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4664 // Smis should never trigger transitions.
4665 ASSERT(!value->IsSmi());
4666
4667 if (value->IsNumber()) {
4668 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4669 TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4670 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4671 FixedDoubleArray* double_array =
4672 FixedDoubleArray::cast(object->elements());
4673 HeapNumber* number = HeapNumber::cast(*value);
4674 double_array->set(store_index, number->Number());
4675 } else {
4676 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4677 elements_kind == FAST_DOUBLE_ELEMENTS);
4678 TransitionElementsKind(object, FAST_ELEMENTS);
4679 FixedArray* object_array =
4680 FixedArray::cast(object->elements());
4681 object_array->set(store_index, *value);
4682 }
4683 return *object;
4684}
4685
4686
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004687// Set a local property, even if it is READ_ONLY. If the property does not
4688// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004689RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004691 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004692 CONVERT_CHECKED(JSObject, object, args[0]);
4693 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004694 // Compute attributes.
4695 PropertyAttributes attributes = NONE;
4696 if (args.length() == 4) {
4697 CONVERT_CHECKED(Smi, value_obj, args[3]);
4698 int unchecked_value = value_obj->value();
4699 // Only attribute bits should be set.
4700 RUNTIME_ASSERT(
4701 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4702 attributes = static_cast<PropertyAttributes>(unchecked_value);
4703 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004705 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004706 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707}
4708
4709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004710RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004711 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004712 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004714 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004716 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004717 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004718 ? JSReceiver::STRICT_DELETION
4719 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720}
4721
4722
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004723static Object* HasLocalPropertyImplementation(Isolate* isolate,
4724 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004725 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004726 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004727 // Handle hidden prototypes. If there's a hidden prototype above this thing
4728 // then we have to check it for properties, because they are supposed to
4729 // look like they are on this object.
4730 Handle<Object> proto(object->GetPrototype());
4731 if (proto->IsJSObject() &&
4732 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004733 return HasLocalPropertyImplementation(isolate,
4734 Handle<JSObject>::cast(proto),
4735 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004736 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004737 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004738}
4739
4740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004741RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742 NoHandleAllocation ha;
4743 ASSERT(args.length() == 2);
4744 CONVERT_CHECKED(String, key, args[1]);
4745
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004746 uint32_t index;
4747 const bool key_is_array_index = key->AsArrayIndex(&index);
4748
ager@chromium.org9085a012009-05-11 19:22:57 +00004749 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004751 if (obj->IsJSObject()) {
4752 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004753 // Fast case: either the key is a real named property or it is not
4754 // an array index and there are no interceptors or hidden
4755 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004756 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004757 Map* map = object->map();
4758 if (!key_is_array_index &&
4759 !map->has_named_interceptor() &&
4760 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4761 return isolate->heap()->false_value();
4762 }
4763 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004764 HandleScope scope(isolate);
4765 return HasLocalPropertyImplementation(isolate,
4766 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004767 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004768 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004770 String* string = String::cast(obj);
4771 if (index < static_cast<uint32_t>(string->length())) {
4772 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004773 }
4774 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004775 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776}
4777
4778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004779RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004780 NoHandleAllocation na;
4781 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004782 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4783 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004785 bool result = receiver->HasProperty(key);
4786 if (isolate->has_pending_exception()) return Failure::Exception();
4787 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004788}
4789
4790
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004791RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004792 NoHandleAllocation na;
4793 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004794 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4795 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004796
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004797 bool result = receiver->HasElement(index->value());
4798 if (isolate->has_pending_exception()) return Failure::Exception();
4799 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004800}
4801
4802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004803RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004804 NoHandleAllocation ha;
4805 ASSERT(args.length() == 2);
4806
4807 CONVERT_CHECKED(JSObject, object, args[0]);
4808 CONVERT_CHECKED(String, key, args[1]);
4809
4810 uint32_t index;
4811 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004812 JSObject::LocalElementType type = object->HasLocalElement(index);
4813 switch (type) {
4814 case JSObject::UNDEFINED_ELEMENT:
4815 case JSObject::STRING_CHARACTER_ELEMENT:
4816 return isolate->heap()->false_value();
4817 case JSObject::INTERCEPTED_ELEMENT:
4818 case JSObject::FAST_ELEMENT:
4819 return isolate->heap()->true_value();
4820 case JSObject::DICTIONARY_ELEMENT: {
4821 if (object->IsJSGlobalProxy()) {
4822 Object* proto = object->GetPrototype();
4823 if (proto->IsNull()) {
4824 return isolate->heap()->false_value();
4825 }
4826 ASSERT(proto->IsJSGlobalObject());
4827 object = JSObject::cast(proto);
4828 }
4829 FixedArray* elements = FixedArray::cast(object->elements());
4830 NumberDictionary* dictionary = NULL;
4831 if (elements->map() ==
4832 isolate->heap()->non_strict_arguments_elements_map()) {
4833 dictionary = NumberDictionary::cast(elements->get(1));
4834 } else {
4835 dictionary = NumberDictionary::cast(elements);
4836 }
4837 int entry = dictionary->FindEntry(index);
4838 ASSERT(entry != NumberDictionary::kNotFound);
4839 PropertyDetails details = dictionary->DetailsAt(entry);
4840 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4841 }
4842 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 }
4844
ager@chromium.org870a0b62008-11-04 11:43:05 +00004845 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004846 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847}
4848
4849
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004850RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004851 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004852 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004853 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4854 bool threw = false;
4855 Handle<JSArray> result = GetKeysFor(object, &threw);
4856 if (threw) return Failure::Exception();
4857 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858}
4859
4860
4861// Returns either a FixedArray as Runtime_GetPropertyNames,
4862// or, if the given object has an enum cache that contains
4863// all enumerable properties of the object and its prototypes
4864// have none, the map of the object. This is used to speed up
4865// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004866RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004867 ASSERT(args.length() == 1);
4868
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004869 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870
4871 if (raw_object->IsSimpleEnum()) return raw_object->map();
4872
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004873 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004874 Handle<JSReceiver> object(raw_object);
4875 bool threw = false;
4876 Handle<FixedArray> content =
4877 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4878 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004879
4880 // Test again, since cache may have been built by preceding call.
4881 if (object->IsSimpleEnum()) return object->map();
4882
4883 return *content;
4884}
4885
4886
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004887// Find the length of the prototype chain that is to to handled as one. If a
4888// prototype object is hidden it is to be viewed as part of the the object it
4889// is prototype for.
4890static int LocalPrototypeChainLength(JSObject* obj) {
4891 int count = 1;
4892 Object* proto = obj->GetPrototype();
4893 while (proto->IsJSObject() &&
4894 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4895 count++;
4896 proto = JSObject::cast(proto)->GetPrototype();
4897 }
4898 return count;
4899}
4900
4901
4902// Return the names of the local named properties.
4903// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004904RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004905 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004906 ASSERT(args.length() == 1);
4907 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004908 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004909 }
4910 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4911
4912 // Skip the global proxy as it has no properties and always delegates to the
4913 // real global object.
4914 if (obj->IsJSGlobalProxy()) {
4915 // Only collect names if access is permitted.
4916 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004917 !isolate->MayNamedAccess(*obj,
4918 isolate->heap()->undefined_value(),
4919 v8::ACCESS_KEYS)) {
4920 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4921 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004922 }
4923 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4924 }
4925
4926 // Find the number of objects making up this.
4927 int length = LocalPrototypeChainLength(*obj);
4928
4929 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004930 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004931 int total_property_count = 0;
4932 Handle<JSObject> jsproto = obj;
4933 for (int i = 0; i < length; i++) {
4934 // Only collect names if access is permitted.
4935 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004936 !isolate->MayNamedAccess(*jsproto,
4937 isolate->heap()->undefined_value(),
4938 v8::ACCESS_KEYS)) {
4939 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4940 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004941 }
4942 int n;
4943 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4944 local_property_count[i] = n;
4945 total_property_count += n;
4946 if (i < length - 1) {
4947 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4948 }
4949 }
4950
4951 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004952 Handle<FixedArray> names =
4953 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004954
4955 // Get the property names.
4956 jsproto = obj;
4957 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004958 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004959 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004960 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4961 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004962 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004963 proto_with_hidden_properties++;
4964 }
4965 if (i < length - 1) {
4966 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4967 }
4968 }
4969
4970 // Filter out name of hidden propeties object.
4971 if (proto_with_hidden_properties > 0) {
4972 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004973 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004974 names->length() - proto_with_hidden_properties);
4975 int dest_pos = 0;
4976 for (int i = 0; i < total_property_count; i++) {
4977 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004978 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004979 continue;
4980 }
4981 names->set(dest_pos++, name);
4982 }
4983 }
4984
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004985 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004986}
4987
4988
4989// Return the names of the local indexed properties.
4990// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004991RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004992 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004993 ASSERT(args.length() == 1);
4994 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004996 }
4997 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4998
4999 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005000 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005001 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005002 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005003}
5004
5005
5006// Return information on whether an object has a named or indexed interceptor.
5007// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005008RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005010 ASSERT(args.length() == 1);
5011 if (!args[0]->IsJSObject()) {
5012 return Smi::FromInt(0);
5013 }
5014 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5015
5016 int result = 0;
5017 if (obj->HasNamedInterceptor()) result |= 2;
5018 if (obj->HasIndexedInterceptor()) result |= 1;
5019
5020 return Smi::FromInt(result);
5021}
5022
5023
5024// Return property names from named interceptor.
5025// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005026RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005027 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005028 ASSERT(args.length() == 1);
5029 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5030
5031 if (obj->HasNamedInterceptor()) {
5032 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5033 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5034 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005035 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005036}
5037
5038
5039// Return element names from indexed interceptor.
5040// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005041RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005042 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005043 ASSERT(args.length() == 1);
5044 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5045
5046 if (obj->HasIndexedInterceptor()) {
5047 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5048 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5049 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005050 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005051}
5052
5053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005054RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005055 ASSERT_EQ(args.length(), 1);
5056 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005057 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005058 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005059
5060 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005061 // Do access checks before going to the global object.
5062 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005063 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005064 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005065 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5066 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005067 }
5068
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005069 Handle<Object> proto(object->GetPrototype());
5070 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005071 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005072 object = Handle<JSObject>::cast(proto);
5073 }
5074
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005075 bool threw = false;
5076 Handle<FixedArray> contents =
5077 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5078 if (threw) return Failure::Exception();
5079
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005080 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5081 // property array and since the result is mutable we have to create
5082 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005083 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005084 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005085 for (int i = 0; i < length; i++) {
5086 Object* entry = contents->get(i);
5087 if (entry->IsString()) {
5088 copy->set(i, entry);
5089 } else {
5090 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005091 HandleScope scope(isolate);
5092 Handle<Object> entry_handle(entry, isolate);
5093 Handle<Object> entry_str =
5094 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005095 copy->set(i, *entry_str);
5096 }
5097 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005098 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005099}
5100
5101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005102RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005103 NoHandleAllocation ha;
5104 ASSERT(args.length() == 1);
5105
5106 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005107 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005108 it.AdvanceToArgumentsFrame();
5109 JavaScriptFrame* frame = it.frame();
5110
5111 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005112 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113
5114 // Try to convert the key to an index. If successful and within
5115 // index return the the argument from the frame.
5116 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005117 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005118 return frame->GetParameter(index);
5119 }
5120
5121 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005122 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005123 bool exception = false;
5124 Handle<Object> converted =
5125 Execution::ToString(args.at<Object>(0), &exception);
5126 if (exception) return Failure::Exception();
5127 Handle<String> key = Handle<String>::cast(converted);
5128
5129 // Try to convert the string key into an array index.
5130 if (key->AsArrayIndex(&index)) {
5131 if (index < n) {
5132 return frame->GetParameter(index);
5133 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005134 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005135 }
5136 }
5137
5138 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005139 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5140 if (key->Equals(isolate->heap()->callee_symbol())) {
5141 Object* function = frame->function();
5142 if (function->IsJSFunction() &&
5143 JSFunction::cast(function)->shared()->strict_mode()) {
5144 return isolate->Throw(*isolate->factory()->NewTypeError(
5145 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5146 }
5147 return function;
5148 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005149
5150 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005151 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005152}
5153
5154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005155RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005156 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005157
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005158 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005159 Handle<Object> object = args.at<Object>(0);
5160 if (object->IsJSObject()) {
5161 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005162 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005163 MaybeObject* ok = js_object->TransformToFastProperties(0);
5164 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005165 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005166 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005167 return *object;
5168}
5169
5170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005171RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005172 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005173
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005174 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005175 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005176 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005177 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005178 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005179 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005180 return *object;
5181}
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);
5259 CONVERT_CHECKED(String, subject, args[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
5315 CONVERT_CHECKED(JSArray, codes, args[0]);
5316 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);
5395 CONVERT_CHECKED(String, source, args[0]);
5396
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);
5513 CONVERT_CHECKED(String, source, args[0]);
5514
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;
5770 CONVERT_CHECKED(String, str, args[0]);
5771 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;
5794 CONVERT_CHECKED(String, str, args[0]);
5795 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);
5871 CONVERT_CHECKED(JSArray, array, args[0]);
5872
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
5913 CONVERT_CHECKED(String, s, args[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;
5926 CONVERT_CHECKED(String, str, args[0]);
5927
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 //
5951 // NOTE: This assumes that the upper/lower case of an ascii
5952 // character is also ascii. This is currently the case, but it
5953 // 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
6052// ascii (less than 0x7F).
6053static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6054 // Every byte in an ascii string is less than or equal to 0x7F.
6055 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;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006175 CONVERT_CHECKED(String, s, args[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
6182 // Simpler handling of ascii strings.
6183 //
6184 // NOTE: This assumes that the upper/lower case of an ascii
6185 // character is also ascii. This is currently the case, but it
6186 // 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
6237 CONVERT_CHECKED(String, s, args[0]);
6238 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6239 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6240
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);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006264 CONVERT_ARG_CHECKED(String, subject, 0);
6265 CONVERT_ARG_CHECKED(String, pattern, 1);
6266 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);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006312 MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
6313 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
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006348// Copies ascii characters to the given fixed array looking up
6349// 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);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006386 CONVERT_ARG_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);
6437 CONVERT_CHECKED(String, value, args[0]);
6438 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);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628 CONVERT_CHECKED(String, str1, args[0]);
6629 CONVERT_CHECKED(String, str2, args[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);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677 CONVERT_CHECKED(JSArray, array, args[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);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006683 CONVERT_CHECKED(String, special, args[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
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006688 MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
6689 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 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006754 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006755 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006756 return Failure::OutOfMemoryException();
6757 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006758 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759 }
6760
6761 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006763
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006765 { MaybeObject* maybe_object =
6766 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006767 if (!maybe_object->ToObject(&object)) return maybe_object;
6768 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006769 SeqAsciiString* answer = SeqAsciiString::cast(object);
6770 StringBuilderConcatHelper(special,
6771 answer->GetChars(),
6772 fixed_array,
6773 array_length);
6774 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006775 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006776 { MaybeObject* maybe_object =
6777 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006778 if (!maybe_object->ToObject(&object)) return maybe_object;
6779 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006780 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6781 StringBuilderConcatHelper(special,
6782 answer->GetChars(),
6783 fixed_array,
6784 array_length);
6785 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006786 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787}
6788
6789
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006790RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006791 NoHandleAllocation ha;
6792 ASSERT(args.length() == 3);
6793 CONVERT_CHECKED(JSArray, array, args[0]);
6794 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006795 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006796 return Failure::OutOfMemoryException();
6797 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006798 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006799 CONVERT_CHECKED(String, separator, args[2]);
6800
6801 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006802 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006803 }
6804 FixedArray* fixed_array = FixedArray::cast(array->elements());
6805 if (fixed_array->length() < array_length) {
6806 array_length = fixed_array->length();
6807 }
6808
6809 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006810 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006811 } else if (array_length == 1) {
6812 Object* first = fixed_array->get(0);
6813 if (first->IsString()) return first;
6814 }
6815
6816 int separator_length = separator->length();
6817 int max_nof_separators =
6818 (String::kMaxLength + separator_length - 1) / separator_length;
6819 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006820 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006821 return Failure::OutOfMemoryException();
6822 }
6823 int length = (array_length - 1) * separator_length;
6824 for (int i = 0; i < array_length; i++) {
6825 Object* element_obj = fixed_array->get(i);
6826 if (!element_obj->IsString()) {
6827 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006828 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006829 }
6830 String* element = String::cast(element_obj);
6831 int increment = element->length();
6832 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006833 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006834 return Failure::OutOfMemoryException();
6835 }
6836 length += increment;
6837 }
6838
6839 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006840 { MaybeObject* maybe_object =
6841 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006842 if (!maybe_object->ToObject(&object)) return maybe_object;
6843 }
6844 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6845
6846 uc16* sink = answer->GetChars();
6847#ifdef DEBUG
6848 uc16* end = sink + length;
6849#endif
6850
6851 String* first = String::cast(fixed_array->get(0));
6852 int first_length = first->length();
6853 String::WriteToFlat(first, sink, 0, first_length);
6854 sink += first_length;
6855
6856 for (int i = 1; i < array_length; i++) {
6857 ASSERT(sink + separator_length <= end);
6858 String::WriteToFlat(separator, sink, 0, separator_length);
6859 sink += separator_length;
6860
6861 String* element = String::cast(fixed_array->get(i));
6862 int element_length = element->length();
6863 ASSERT(sink + element_length <= end);
6864 String::WriteToFlat(element, sink, 0, element_length);
6865 sink += element_length;
6866 }
6867 ASSERT(sink == end);
6868
6869 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6870 return answer;
6871}
6872
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006873template <typename Char>
6874static void JoinSparseArrayWithSeparator(FixedArray* elements,
6875 int elements_length,
6876 uint32_t array_length,
6877 String* separator,
6878 Vector<Char> buffer) {
6879 int previous_separator_position = 0;
6880 int separator_length = separator->length();
6881 int cursor = 0;
6882 for (int i = 0; i < elements_length; i += 2) {
6883 int position = NumberToInt32(elements->get(i));
6884 String* string = String::cast(elements->get(i + 1));
6885 int string_length = string->length();
6886 if (string->length() > 0) {
6887 while (previous_separator_position < position) {
6888 String::WriteToFlat<Char>(separator, &buffer[cursor],
6889 0, separator_length);
6890 cursor += separator_length;
6891 previous_separator_position++;
6892 }
6893 String::WriteToFlat<Char>(string, &buffer[cursor],
6894 0, string_length);
6895 cursor += string->length();
6896 }
6897 }
6898 if (separator_length > 0) {
6899 // Array length must be representable as a signed 32-bit number,
6900 // otherwise the total string length would have been too large.
6901 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6902 int last_array_index = static_cast<int>(array_length - 1);
6903 while (previous_separator_position < last_array_index) {
6904 String::WriteToFlat<Char>(separator, &buffer[cursor],
6905 0, separator_length);
6906 cursor += separator_length;
6907 previous_separator_position++;
6908 }
6909 }
6910 ASSERT(cursor <= buffer.length());
6911}
6912
6913
6914RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6915 NoHandleAllocation ha;
6916 ASSERT(args.length() == 3);
6917 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006918 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6919 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006920 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6921 CONVERT_CHECKED(String, separator, args[2]);
6922 // elements_array is fast-mode JSarray of alternating positions
6923 // (increasing order) and strings.
6924 // array_length is length of original array (used to add separators);
6925 // separator is string to put between elements. Assumed to be non-empty.
6926
6927 // Find total length of join result.
6928 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006929 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006930 int max_string_length;
6931 if (is_ascii) {
6932 max_string_length = SeqAsciiString::kMaxLength;
6933 } else {
6934 max_string_length = SeqTwoByteString::kMaxLength;
6935 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006936 bool overflow = false;
6937 CONVERT_NUMBER_CHECKED(int, elements_length,
6938 Int32, elements_array->length());
6939 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6940 FixedArray* elements = FixedArray::cast(elements_array->elements());
6941 for (int i = 0; i < elements_length; i += 2) {
6942 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6943 CONVERT_CHECKED(String, string, elements->get(i + 1));
6944 int length = string->length();
6945 if (is_ascii && !string->IsAsciiRepresentation()) {
6946 is_ascii = false;
6947 max_string_length = SeqTwoByteString::kMaxLength;
6948 }
6949 if (length > max_string_length ||
6950 max_string_length - length < string_length) {
6951 overflow = true;
6952 break;
6953 }
6954 string_length += length;
6955 }
6956 int separator_length = separator->length();
6957 if (!overflow && separator_length > 0) {
6958 if (array_length <= 0x7fffffffu) {
6959 int separator_count = static_cast<int>(array_length) - 1;
6960 int remaining_length = max_string_length - string_length;
6961 if ((remaining_length / separator_length) >= separator_count) {
6962 string_length += separator_length * (array_length - 1);
6963 } else {
6964 // Not room for the separators within the maximal string length.
6965 overflow = true;
6966 }
6967 } else {
6968 // Nonempty separator and at least 2^31-1 separators necessary
6969 // means that the string is too large to create.
6970 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6971 overflow = true;
6972 }
6973 }
6974 if (overflow) {
6975 // Throw OutOfMemory exception for creating too large a string.
6976 V8::FatalProcessOutOfMemory("Array join result too large.");
6977 }
6978
6979 if (is_ascii) {
6980 MaybeObject* result_allocation =
6981 isolate->heap()->AllocateRawAsciiString(string_length);
6982 if (result_allocation->IsFailure()) return result_allocation;
6983 SeqAsciiString* result_string =
6984 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6985 JoinSparseArrayWithSeparator<char>(elements,
6986 elements_length,
6987 array_length,
6988 separator,
6989 Vector<char>(result_string->GetChars(),
6990 string_length));
6991 return result_string;
6992 } else {
6993 MaybeObject* result_allocation =
6994 isolate->heap()->AllocateRawTwoByteString(string_length);
6995 if (result_allocation->IsFailure()) return result_allocation;
6996 SeqTwoByteString* result_string =
6997 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6998 JoinSparseArrayWithSeparator<uc16>(elements,
6999 elements_length,
7000 array_length,
7001 separator,
7002 Vector<uc16>(result_string->GetChars(),
7003 string_length));
7004 return result_string;
7005 }
7006}
7007
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007009RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007010 NoHandleAllocation ha;
7011 ASSERT(args.length() == 2);
7012
7013 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7014 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007015 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007016}
7017
7018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007019RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007020 NoHandleAllocation ha;
7021 ASSERT(args.length() == 2);
7022
7023 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7024 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007025 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007026}
7027
7028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007029RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007030 NoHandleAllocation ha;
7031 ASSERT(args.length() == 2);
7032
7033 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7034 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007035 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007036}
7037
7038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007039RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007040 NoHandleAllocation ha;
7041 ASSERT(args.length() == 1);
7042
7043 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007044 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045}
7046
7047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007048RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007049 NoHandleAllocation ha;
7050 ASSERT(args.length() == 2);
7051
7052 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7053 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007054 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055}
7056
7057
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007058RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007059 NoHandleAllocation ha;
7060 ASSERT(args.length() == 2);
7061
7062 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7063 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007064 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007065}
7066
7067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007068RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007069 NoHandleAllocation ha;
7070 ASSERT(args.length() == 2);
7071
7072 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7073 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007074 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007075}
7076
7077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007078RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007079 NoHandleAllocation ha;
7080 ASSERT(args.length() == 2);
7081
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007082 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7083 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7085 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7086 if (x == y) return Smi::FromInt(EQUAL);
7087 Object* result;
7088 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7089 result = Smi::FromInt(EQUAL);
7090 } else {
7091 result = Smi::FromInt(NOT_EQUAL);
7092 }
7093 return result;
7094}
7095
7096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007097RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098 NoHandleAllocation ha;
7099 ASSERT(args.length() == 2);
7100
7101 CONVERT_CHECKED(String, x, args[0]);
7102 CONVERT_CHECKED(String, y, args[1]);
7103
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007104 bool not_equal = !x->Equals(y);
7105 // This is slightly convoluted because the value that signifies
7106 // equality is 0 and inequality is 1 so we have to negate the result
7107 // from String::Equals.
7108 ASSERT(not_equal == 0 || not_equal == 1);
7109 STATIC_CHECK(EQUAL == 0);
7110 STATIC_CHECK(NOT_EQUAL == 1);
7111 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007112}
7113
7114
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007115RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116 NoHandleAllocation ha;
7117 ASSERT(args.length() == 3);
7118
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007119 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7120 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007121 if (isnan(x) || isnan(y)) return args[2];
7122 if (x == y) return Smi::FromInt(EQUAL);
7123 if (isless(x, y)) return Smi::FromInt(LESS);
7124 return Smi::FromInt(GREATER);
7125}
7126
7127
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007128// Compare two Smis as if they were converted to strings and then
7129// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007130RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007131 NoHandleAllocation ha;
7132 ASSERT(args.length() == 2);
7133
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007134 // Extract the integer values from the Smis.
7135 CONVERT_CHECKED(Smi, x, args[0]);
7136 CONVERT_CHECKED(Smi, y, args[1]);
7137 int x_value = x->value();
7138 int y_value = y->value();
7139
7140 // If the integers are equal so are the string representations.
7141 if (x_value == y_value) return Smi::FromInt(EQUAL);
7142
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007143 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007144 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007145 if (x_value == 0 || y_value == 0)
7146 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007147
ager@chromium.org32912102009-01-16 10:38:43 +00007148 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007149 // smallest because the char code of '-' is less than the char code
7150 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007151
7152 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7153 // architectures using 32-bit Smis.
7154 uint32_t x_scaled = x_value;
7155 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007156 if (x_value < 0 || y_value < 0) {
7157 if (y_value >= 0) return Smi::FromInt(LESS);
7158 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007159 x_scaled = -x_value;
7160 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007161 }
7162
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007163 static const uint32_t kPowersOf10[] = {
7164 1, 10, 100, 1000, 10*1000, 100*1000,
7165 1000*1000, 10*1000*1000, 100*1000*1000,
7166 1000*1000*1000
7167 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007168
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007169 // If the integers have the same number of decimal digits they can be
7170 // compared directly as the numeric order is the same as the
7171 // lexicographic order. If one integer has fewer digits, it is scaled
7172 // by some power of 10 to have the same number of digits as the longer
7173 // integer. If the scaled integers are equal it means the shorter
7174 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007175
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007176 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7177 int x_log2 = IntegerLog2(x_scaled);
7178 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7179 x_log10 -= x_scaled < kPowersOf10[x_log10];
7180
7181 int y_log2 = IntegerLog2(y_scaled);
7182 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7183 y_log10 -= y_scaled < kPowersOf10[y_log10];
7184
7185 int tie = EQUAL;
7186
7187 if (x_log10 < y_log10) {
7188 // X has fewer digits. We would like to simply scale up X but that
7189 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7190 // be scaled up to 9_000_000_000. So we scale up by the next
7191 // smallest power and scale down Y to drop one digit. It is OK to
7192 // drop one digit from the longer integer since the final digit is
7193 // past the length of the shorter integer.
7194 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7195 y_scaled /= 10;
7196 tie = LESS;
7197 } else if (y_log10 < x_log10) {
7198 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7199 x_scaled /= 10;
7200 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007201 }
7202
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007203 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7204 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7205 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007206}
7207
7208
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007209static Object* StringInputBufferCompare(RuntimeState* state,
7210 String* x,
7211 String* y) {
7212 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7213 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007214 bufx.Reset(x);
7215 bufy.Reset(y);
7216 while (bufx.has_more() && bufy.has_more()) {
7217 int d = bufx.GetNext() - bufy.GetNext();
7218 if (d < 0) return Smi::FromInt(LESS);
7219 else if (d > 0) return Smi::FromInt(GREATER);
7220 }
7221
7222 // x is (non-trivial) prefix of y:
7223 if (bufy.has_more()) return Smi::FromInt(LESS);
7224 // y is prefix of x:
7225 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7226}
7227
7228
7229static Object* FlatStringCompare(String* x, String* y) {
7230 ASSERT(x->IsFlat());
7231 ASSERT(y->IsFlat());
7232 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7233 int prefix_length = x->length();
7234 if (y->length() < prefix_length) {
7235 prefix_length = y->length();
7236 equal_prefix_result = Smi::FromInt(GREATER);
7237 } else if (y->length() > prefix_length) {
7238 equal_prefix_result = Smi::FromInt(LESS);
7239 }
7240 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007241 String::FlatContent x_content = x->GetFlatContent();
7242 String::FlatContent y_content = y->GetFlatContent();
7243 if (x_content.IsAscii()) {
7244 Vector<const char> x_chars = x_content.ToAsciiVector();
7245 if (y_content.IsAscii()) {
7246 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007247 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007248 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007249 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007250 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7251 }
7252 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007253 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7254 if (y_content.IsAscii()) {
7255 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007256 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7257 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007258 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007259 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7260 }
7261 }
7262 Object* result;
7263 if (r == 0) {
7264 result = equal_prefix_result;
7265 } else {
7266 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7267 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007268 ASSERT(result ==
7269 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007270 return result;
7271}
7272
7273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007274RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007275 NoHandleAllocation ha;
7276 ASSERT(args.length() == 2);
7277
7278 CONVERT_CHECKED(String, x, args[0]);
7279 CONVERT_CHECKED(String, y, args[1]);
7280
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007281 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283 // A few fast case tests before we flatten.
7284 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007285 if (y->length() == 0) {
7286 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007287 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007288 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007289 return Smi::FromInt(LESS);
7290 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007291
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007292 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007293 if (d < 0) return Smi::FromInt(LESS);
7294 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007295
lrn@chromium.org303ada72010-10-27 09:33:13 +00007296 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007297 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007298 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7299 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007300 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007301 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7302 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007304 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007305 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007306}
7307
7308
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007309RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007310 NoHandleAllocation ha;
7311 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007312 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007314 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007315 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007316}
7317
7318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007319RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007320 NoHandleAllocation ha;
7321 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007322 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007323
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007324 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007325 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007326}
7327
7328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007329RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007330 NoHandleAllocation ha;
7331 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007332 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007334 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007335 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007336}
7337
7338
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007339static const double kPiDividedBy4 = 0.78539816339744830962;
7340
7341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007342RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007343 NoHandleAllocation ha;
7344 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007345 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007347 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7348 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349 double result;
7350 if (isinf(x) && isinf(y)) {
7351 // Make sure that the result in case of two infinite arguments
7352 // is a multiple of Pi / 4. The sign of the result is determined
7353 // by the first argument (x) and the sign of the second argument
7354 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007355 int multiplier = (x < 0) ? -1 : 1;
7356 if (y < 0) multiplier *= 3;
7357 result = multiplier * kPiDividedBy4;
7358 } else {
7359 result = atan2(x, y);
7360 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007361 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007362}
7363
7364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007365RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007366 NoHandleAllocation ha;
7367 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007368 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007370 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007371 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372}
7373
7374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007375RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376 NoHandleAllocation ha;
7377 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007378 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007380 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007381 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007382}
7383
7384
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007385RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386 NoHandleAllocation ha;
7387 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007388 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007390 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007391 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392}
7393
7394
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007395RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007396 NoHandleAllocation ha;
7397 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007398 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007399
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007400 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007401 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007402}
7403
7404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007405RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007406 NoHandleAllocation ha;
7407 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007408 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007409
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007410 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007411 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007412}
7413
7414
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007415RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007416 NoHandleAllocation ha;
7417 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007418 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007419
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007420 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007421
7422 // If the second argument is a smi, it is much faster to call the
7423 // custom powi() function than the generic pow().
7424 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007425 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007426 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007427 }
7428
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007429 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007430 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007431}
7432
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007433// Fast version of Math.pow if we know that y is not an integer and
7434// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007435RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007436 NoHandleAllocation ha;
7437 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007438 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7439 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007440 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007441 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007442 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007443 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007444 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007445 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007446 }
7447}
7448
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007450RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451 NoHandleAllocation ha;
7452 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007453 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007455 if (!args[0]->IsHeapNumber()) {
7456 // Must be smi. Return the argument unchanged for all the other types
7457 // to make fuzz-natives test happy.
7458 return args[0];
7459 }
7460
7461 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7462
7463 double value = number->value();
7464 int exponent = number->get_exponent();
7465 int sign = number->get_sign();
7466
danno@chromium.org160a7b02011-04-18 15:51:38 +00007467 if (exponent < -1) {
7468 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7469 if (sign) return isolate->heap()->minus_zero_value();
7470 return Smi::FromInt(0);
7471 }
7472
7473 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7474 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7475 // agument holds for 32-bit smis).
7476 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007477 return Smi::FromInt(static_cast<int>(value + 0.5));
7478 }
7479
7480 // If the magnitude is big enough, there's no place for fraction part. If we
7481 // try to add 0.5 to this number, 1.0 will be added instead.
7482 if (exponent >= 52) {
7483 return number;
7484 }
7485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007486 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007487
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007488 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007489 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490}
7491
7492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007493RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007494 NoHandleAllocation ha;
7495 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007496 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007497
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007498 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007499 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007500}
7501
7502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007503RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007504 NoHandleAllocation ha;
7505 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007506 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007507
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007508 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007509 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007510}
7511
7512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007513RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007514 NoHandleAllocation ha;
7515 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007516 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007517
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007518 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007519 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520}
7521
7522
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007523static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007524 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7525 181, 212, 243, 273, 304, 334};
7526 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7527 182, 213, 244, 274, 305, 335};
7528
7529 year += month / 12;
7530 month %= 12;
7531 if (month < 0) {
7532 year--;
7533 month += 12;
7534 }
7535
7536 ASSERT(month >= 0);
7537 ASSERT(month < 12);
7538
7539 // year_delta is an arbitrary number such that:
7540 // a) year_delta = -1 (mod 400)
7541 // b) year + year_delta > 0 for years in the range defined by
7542 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7543 // Jan 1 1970. This is required so that we don't run into integer
7544 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007545 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007546 // operations.
7547 static const int year_delta = 399999;
7548 static const int base_day = 365 * (1970 + year_delta) +
7549 (1970 + year_delta) / 4 -
7550 (1970 + year_delta) / 100 +
7551 (1970 + year_delta) / 400;
7552
7553 int year1 = year + year_delta;
7554 int day_from_year = 365 * year1 +
7555 year1 / 4 -
7556 year1 / 100 +
7557 year1 / 400 -
7558 base_day;
7559
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007560 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7561 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007562 }
7563
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007564 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007565}
7566
7567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007568RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007569 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007570 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007571
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007572 CONVERT_SMI_ARG_CHECKED(year, 0);
7573 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007574
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007575 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007576}
7577
7578
7579static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7580static const int kDaysIn4Years = 4 * 365 + 1;
7581static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7582static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7583static const int kDays1970to2000 = 30 * 365 + 7;
7584static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7585 kDays1970to2000;
7586static const int kYearsOffset = 400000;
7587
7588static const char kDayInYear[] = {
7589 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7590 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7591 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7592 22, 23, 24, 25, 26, 27, 28,
7593 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7594 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7595 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7596 22, 23, 24, 25, 26, 27, 28, 29, 30,
7597 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7598 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7599 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7600 22, 23, 24, 25, 26, 27, 28, 29, 30,
7601 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7602 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7603 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7604 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7605 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7606 22, 23, 24, 25, 26, 27, 28, 29, 30,
7607 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7608 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7609 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7610 22, 23, 24, 25, 26, 27, 28, 29, 30,
7611 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7612 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7613
7614 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7615 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7616 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7617 22, 23, 24, 25, 26, 27, 28,
7618 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7619 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7620 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7621 22, 23, 24, 25, 26, 27, 28, 29, 30,
7622 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7623 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7624 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7625 22, 23, 24, 25, 26, 27, 28, 29, 30,
7626 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7627 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7628 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7629 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7630 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7631 22, 23, 24, 25, 26, 27, 28, 29, 30,
7632 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7633 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7634 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7635 22, 23, 24, 25, 26, 27, 28, 29, 30,
7636 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7637 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7638
7639 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7640 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7641 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7642 22, 23, 24, 25, 26, 27, 28, 29,
7643 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7644 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7645 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7646 22, 23, 24, 25, 26, 27, 28, 29, 30,
7647 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7648 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7649 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7650 22, 23, 24, 25, 26, 27, 28, 29, 30,
7651 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7652 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7653 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7654 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7655 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7656 22, 23, 24, 25, 26, 27, 28, 29, 30,
7657 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7658 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7659 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7660 22, 23, 24, 25, 26, 27, 28, 29, 30,
7661 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7662 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7663
7664 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7665 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7666 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7667 22, 23, 24, 25, 26, 27, 28,
7668 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7669 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7670 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7671 22, 23, 24, 25, 26, 27, 28, 29, 30,
7672 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7673 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7674 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7675 22, 23, 24, 25, 26, 27, 28, 29, 30,
7676 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7677 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7678 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7679 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7680 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7681 22, 23, 24, 25, 26, 27, 28, 29, 30,
7682 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7683 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7684 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7685 22, 23, 24, 25, 26, 27, 28, 29, 30,
7686 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7687 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7688
7689static const char kMonthInYear[] = {
7690 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7691 0, 0, 0, 0, 0, 0,
7692 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7693 1, 1, 1,
7694 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7695 2, 2, 2, 2, 2, 2,
7696 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7697 3, 3, 3, 3, 3,
7698 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7699 4, 4, 4, 4, 4, 4,
7700 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7701 5, 5, 5, 5, 5,
7702 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7703 6, 6, 6, 6, 6, 6,
7704 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7705 7, 7, 7, 7, 7, 7,
7706 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7707 8, 8, 8, 8, 8,
7708 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7709 9, 9, 9, 9, 9, 9,
7710 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7711 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7712 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7713 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7714
7715 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7716 0, 0, 0, 0, 0, 0,
7717 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7718 1, 1, 1,
7719 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7720 2, 2, 2, 2, 2, 2,
7721 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7722 3, 3, 3, 3, 3,
7723 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7724 4, 4, 4, 4, 4, 4,
7725 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7726 5, 5, 5, 5, 5,
7727 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7728 6, 6, 6, 6, 6, 6,
7729 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7730 7, 7, 7, 7, 7, 7,
7731 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7732 8, 8, 8, 8, 8,
7733 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7734 9, 9, 9, 9, 9, 9,
7735 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7736 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7737 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7738 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7739
7740 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7741 0, 0, 0, 0, 0, 0,
7742 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7743 1, 1, 1, 1,
7744 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7745 2, 2, 2, 2, 2, 2,
7746 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7747 3, 3, 3, 3, 3,
7748 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7749 4, 4, 4, 4, 4, 4,
7750 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7751 5, 5, 5, 5, 5,
7752 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7753 6, 6, 6, 6, 6, 6,
7754 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7755 7, 7, 7, 7, 7, 7,
7756 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7757 8, 8, 8, 8, 8,
7758 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7759 9, 9, 9, 9, 9, 9,
7760 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7761 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7762 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7763 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7764
7765 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7766 0, 0, 0, 0, 0, 0,
7767 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7768 1, 1, 1,
7769 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7770 2, 2, 2, 2, 2, 2,
7771 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7772 3, 3, 3, 3, 3,
7773 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7774 4, 4, 4, 4, 4, 4,
7775 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7776 5, 5, 5, 5, 5,
7777 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7778 6, 6, 6, 6, 6, 6,
7779 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7780 7, 7, 7, 7, 7, 7,
7781 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7782 8, 8, 8, 8, 8,
7783 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7784 9, 9, 9, 9, 9, 9,
7785 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7786 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7787 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7788 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7789
7790
7791// This function works for dates from 1970 to 2099.
7792static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007793 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007794#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007795 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007796#endif
7797
7798 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7799 date %= kDaysIn4Years;
7800
7801 month = kMonthInYear[date];
7802 day = kDayInYear[date];
7803
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007804 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007805}
7806
7807
7808static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007809 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007810#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007811 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007812#endif
7813
7814 date += kDaysOffset;
7815 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7816 date %= kDaysIn400Years;
7817
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007818 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007819
7820 date--;
7821 int yd1 = date / kDaysIn100Years;
7822 date %= kDaysIn100Years;
7823 year += 100 * yd1;
7824
7825 date++;
7826 int yd2 = date / kDaysIn4Years;
7827 date %= kDaysIn4Years;
7828 year += 4 * yd2;
7829
7830 date--;
7831 int yd3 = date / 365;
7832 date %= 365;
7833 year += yd3;
7834
7835 bool is_leap = (!yd1 || yd2) && !yd3;
7836
7837 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007838 ASSERT(is_leap || (date >= 0));
7839 ASSERT((date < 365) || (is_leap && (date < 366)));
7840 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007841 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7842 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007843
7844 if (is_leap) {
7845 day = kDayInYear[2*365 + 1 + date];
7846 month = kMonthInYear[2*365 + 1 + date];
7847 } else {
7848 day = kDayInYear[date];
7849 month = kMonthInYear[date];
7850 }
7851
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007852 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007853}
7854
7855
7856static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007857 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007858 if (date >= 0 && date < 32 * kDaysIn4Years) {
7859 DateYMDFromTimeAfter1970(date, year, month, day);
7860 } else {
7861 DateYMDFromTimeSlow(date, year, month, day);
7862 }
7863}
7864
7865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007866RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007867 NoHandleAllocation ha;
7868 ASSERT(args.length() == 2);
7869
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007870 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007871 CONVERT_CHECKED(JSArray, res_array, args[1]);
7872
7873 int year, month, day;
7874 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7875
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007876 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7877 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007878 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007879
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007880 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7881 if (maybe->IsFailure()) return maybe;
7882 FixedArray* elms = FixedArray::cast(res_array->elements());
7883 elms->set(0, Smi::FromInt(year));
7884 elms->set(1, Smi::FromInt(month));
7885 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007886
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007887 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007888}
7889
7890
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007891RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007892 HandleScope scope(isolate);
7893 ASSERT(args.length() == 3);
7894
7895 Handle<JSFunction> callee = args.at<JSFunction>(0);
7896 Object** parameters = reinterpret_cast<Object**>(args[1]);
7897 const int argument_count = Smi::cast(args[2])->value();
7898
7899 Handle<JSObject> result =
7900 isolate->factory()->NewArgumentsObject(callee, argument_count);
7901 // Allocate the elements if needed.
7902 int parameter_count = callee->shared()->formal_parameter_count();
7903 if (argument_count > 0) {
7904 if (parameter_count > 0) {
7905 int mapped_count = Min(argument_count, parameter_count);
7906 Handle<FixedArray> parameter_map =
7907 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7908 parameter_map->set_map(
7909 isolate->heap()->non_strict_arguments_elements_map());
7910
7911 Handle<Map> old_map(result->map());
7912 Handle<Map> new_map =
7913 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007914 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007915
7916 result->set_map(*new_map);
7917 result->set_elements(*parameter_map);
7918
7919 // Store the context and the arguments array at the beginning of the
7920 // parameter map.
7921 Handle<Context> context(isolate->context());
7922 Handle<FixedArray> arguments =
7923 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7924 parameter_map->set(0, *context);
7925 parameter_map->set(1, *arguments);
7926
7927 // Loop over the actual parameters backwards.
7928 int index = argument_count - 1;
7929 while (index >= mapped_count) {
7930 // These go directly in the arguments array and have no
7931 // corresponding slot in the parameter map.
7932 arguments->set(index, *(parameters - index - 1));
7933 --index;
7934 }
7935
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007936 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007937 while (index >= 0) {
7938 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007939 Handle<String> name(scope_info->ParameterName(index));
7940 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007941 bool duplicate = false;
7942 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007943 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007944 duplicate = true;
7945 break;
7946 }
7947 }
7948
7949 if (duplicate) {
7950 // This goes directly in the arguments array with a hole in the
7951 // parameter map.
7952 arguments->set(index, *(parameters - index - 1));
7953 parameter_map->set_the_hole(index + 2);
7954 } else {
7955 // The context index goes in the parameter map with a hole in the
7956 // arguments array.
7957 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007958 for (int j = 0; j < context_local_count; ++j) {
7959 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007960 context_index = j;
7961 break;
7962 }
7963 }
7964 ASSERT(context_index >= 0);
7965 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007966 parameter_map->set(index + 2, Smi::FromInt(
7967 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007968 }
7969
7970 --index;
7971 }
7972 } else {
7973 // If there is no aliasing, the arguments object elements are not
7974 // special in any way.
7975 Handle<FixedArray> elements =
7976 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7977 result->set_elements(*elements);
7978 for (int i = 0; i < argument_count; ++i) {
7979 elements->set(i, *(parameters - i - 1));
7980 }
7981 }
7982 }
7983 return *result;
7984}
7985
7986
7987RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007988 NoHandleAllocation ha;
7989 ASSERT(args.length() == 3);
7990
7991 JSFunction* callee = JSFunction::cast(args[0]);
7992 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007993 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007994
lrn@chromium.org303ada72010-10-27 09:33:13 +00007995 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007996 { MaybeObject* maybe_result =
7997 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007998 if (!maybe_result->ToObject(&result)) return maybe_result;
7999 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008000 // Allocate the elements if needed.
8001 if (length > 0) {
8002 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008003 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008004 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008005 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8006 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008007
8008 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008009 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008010 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008011 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008012
8013 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008014 for (int i = 0; i < length; i++) {
8015 array->set(i, *--parameters, mode);
8016 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008017 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008018 }
8019 return result;
8020}
8021
8022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008023RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008024 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008025 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008026 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008027 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008028 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008029
whesse@chromium.org7b260152011-06-20 15:33:18 +00008030 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008031 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008032 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008033 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008034 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8035 context,
8036 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008037 return *result;
8038}
8039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008040
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008041// Find the arguments of the JavaScript function invocation that called
8042// into C++ code. Collect these in a newly allocated array of handles (possibly
8043// prefixed by a number of empty handles).
8044static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8045 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008046 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008047 // Find frame containing arguments passed to the caller.
8048 JavaScriptFrameIterator it;
8049 JavaScriptFrame* frame = it.frame();
8050 List<JSFunction*> functions(2);
8051 frame->GetFunctions(&functions);
8052 if (functions.length() > 1) {
8053 int inlined_frame_index = functions.length() - 1;
8054 JSFunction* inlined_function = functions[inlined_frame_index];
8055 int args_count = inlined_function->shared()->formal_parameter_count();
8056 ScopedVector<SlotRef> args_slots(args_count);
8057 SlotRef::ComputeSlotMappingForArguments(frame,
8058 inlined_frame_index,
8059 &args_slots);
8060
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008061 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008062 SmartArrayPointer<Handle<Object> > param_data(
8063 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008064 for (int i = 0; i < args_count; i++) {
8065 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008066 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008067 }
8068 return param_data;
8069 } else {
8070 it.AdvanceToArgumentsFrame();
8071 frame = it.frame();
8072 int args_count = frame->ComputeParametersCount();
8073
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008074 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008075 SmartArrayPointer<Handle<Object> > param_data(
8076 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008077 for (int i = 0; i < args_count; i++) {
8078 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008079 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008080 }
8081 return param_data;
8082 }
8083}
8084
8085
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008086RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8087 HandleScope scope(isolate);
8088 ASSERT(args.length() == 4);
8089 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8090 RUNTIME_ASSERT(args[3]->IsNumber());
8091 Handle<Object> bindee = args.at<Object>(1);
8092
8093 // TODO(lrn): Create bound function in C++ code from premade shared info.
8094 bound_function->shared()->set_bound(true);
8095 // Get all arguments of calling function (Function.prototype.bind).
8096 int argc = 0;
8097 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8098 // Don't count the this-arg.
8099 if (argc > 0) {
8100 ASSERT(*arguments[0] == args[2]);
8101 argc--;
8102 } else {
8103 ASSERT(args[2]->IsUndefined());
8104 }
8105 // Initialize array of bindings (function, this, and any existing arguments
8106 // if the function was already bound).
8107 Handle<FixedArray> new_bindings;
8108 int i;
8109 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8110 Handle<FixedArray> old_bindings(
8111 JSFunction::cast(*bindee)->function_bindings());
8112 new_bindings =
8113 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8114 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8115 i = 0;
8116 for (int n = old_bindings->length(); i < n; i++) {
8117 new_bindings->set(i, old_bindings->get(i));
8118 }
8119 } else {
8120 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8121 new_bindings = isolate->factory()->NewFixedArray(array_size);
8122 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8123 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8124 i = 2;
8125 }
8126 // Copy arguments, skipping the first which is "this_arg".
8127 for (int j = 0; j < argc; j++, i++) {
8128 new_bindings->set(i, *arguments[j + 1]);
8129 }
8130 new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
8131 bound_function->set_function_bindings(*new_bindings);
8132
8133 // Update length.
8134 Handle<String> length_symbol = isolate->factory()->length_symbol();
8135 Handle<Object> new_length(args.at<Object>(3));
8136 PropertyAttributes attr =
8137 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8138 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8139 return *bound_function;
8140}
8141
8142
8143RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8144 HandleScope handles(isolate);
8145 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008146 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008147 if (callable->IsJSFunction()) {
8148 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8149 if (function->shared()->bound()) {
8150 Handle<FixedArray> bindings(function->function_bindings());
8151 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8152 return *isolate->factory()->NewJSArrayWithElements(bindings);
8153 }
8154 }
8155 return isolate->heap()->undefined_value();
8156}
8157
8158
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008159RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008160 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008161 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008162 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008163 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008164 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008165
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008166 // The argument is a bound function. Extract its bound arguments
8167 // and callable.
8168 Handle<FixedArray> bound_args =
8169 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8170 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8171 Handle<Object> bound_function(
8172 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8173 ASSERT(!bound_function->IsJSFunction() ||
8174 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008176 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008177 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008178 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008179 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008180 param_data[i] = Handle<Object>(bound_args->get(
8181 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008182 }
8183
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008184 if (!bound_function->IsJSFunction()) {
8185 bool exception_thrown;
8186 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8187 &exception_thrown);
8188 if (exception_thrown) return Failure::Exception();
8189 }
8190 ASSERT(bound_function->IsJSFunction());
8191
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008192 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008193 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008194 Execution::New(Handle<JSFunction>::cast(bound_function),
8195 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008196 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008197 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008198 }
8199 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008200 return *result;
8201}
8202
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008204static void TrySettingInlineConstructStub(Isolate* isolate,
8205 Handle<JSFunction> function) {
8206 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008207 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008208 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008209 }
8210 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008211 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008212 Handle<Code> code = compiler.CompileConstructStub(function);
8213 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008214 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008215}
8216
8217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008218RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008219 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008220 ASSERT(args.length() == 1);
8221
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008222 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008223
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008224 // If the constructor isn't a proper function we throw a type error.
8225 if (!constructor->IsJSFunction()) {
8226 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8227 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008228 isolate->factory()->NewTypeError("not_constructor", arguments);
8229 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008230 }
8231
8232 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008233
8234 // If function should not have prototype, construction is not allowed. In this
8235 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008236 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008237 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8238 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008239 isolate->factory()->NewTypeError("not_constructor", arguments);
8240 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008241 }
8242
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008243#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008244 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008245 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008246 if (debug->StepInActive()) {
8247 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008248 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008249#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008251 if (function->has_initial_map()) {
8252 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008253 // The 'Function' function ignores the receiver object when
8254 // called using 'new' and creates a new JSFunction object that
8255 // is returned. The receiver object is only used for error
8256 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008257 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008258 // allocate JSFunctions since it does not properly initialize
8259 // the shared part of the function. Since the receiver is
8260 // ignored anyway, we use the global object as the receiver
8261 // instead of a new JSFunction object. This way, errors are
8262 // reported the same way whether or not 'Function' is called
8263 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008264 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008266 }
8267
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008268 // The function should be compiled for the optimization hints to be
8269 // available. We cannot use EnsureCompiled because that forces a
8270 // compilation through the shared function info which makes it
8271 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008272 if (!function->is_compiled()) {
8273 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8274 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008275
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008276 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008277 if (!function->has_initial_map() &&
8278 shared->IsInobjectSlackTrackingInProgress()) {
8279 // The tracking is already in progress for another function. We can only
8280 // track one initial_map at a time, so we force the completion before the
8281 // function is called as a constructor for the first time.
8282 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008283 }
8284
8285 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008286 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8287 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008288 // Delay setting the stub if inobject slack tracking is in progress.
8289 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008290 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008291 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008292
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008293 isolate->counters()->constructed_objects()->Increment();
8294 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008295
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008296 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008297}
8298
8299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008300RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008301 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008302 ASSERT(args.length() == 1);
8303
8304 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8305 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008306 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008307
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008308 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008309}
8310
8311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008312RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008313 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008314 ASSERT(args.length() == 1);
8315
8316 Handle<JSFunction> function = args.at<JSFunction>(0);
8317#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008318 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008320 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321 PrintF("]\n");
8322 }
8323#endif
8324
lrn@chromium.org34e60782011-09-15 07:25:40 +00008325 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008326 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008327 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328 return Failure::Exception();
8329 }
8330
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008331 // All done. Return the compiled code.
8332 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008333 return function->code();
8334}
8335
8336
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008337RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008338 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008339 ASSERT(args.length() == 1);
8340 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008341
8342 // If the function is not compiled ignore the lazy
8343 // recompilation. This can happen if the debugger is activated and
8344 // the function is returned to the not compiled state.
8345 if (!function->shared()->is_compiled()) {
8346 function->ReplaceCode(function->shared()->code());
8347 return function->code();
8348 }
8349
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008350 // If the function is not optimizable or debugger is active continue using the
8351 // code from the full compiler.
8352 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008353 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008354 if (FLAG_trace_opt) {
8355 PrintF("[failed to optimize ");
8356 function->PrintName();
8357 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8358 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008359 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008360 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008361 function->ReplaceCode(function->shared()->code());
8362 return function->code();
8363 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008364 if (JSFunction::CompileOptimized(function,
8365 AstNode::kNoNumber,
8366 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008367 return function->code();
8368 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008369 if (FLAG_trace_opt) {
8370 PrintF("[failed to optimize ");
8371 function->PrintName();
8372 PrintF(": optimized compilation failed]\n");
8373 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008374 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008375 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008376}
8377
8378
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008379class ActivationsFinder : public ThreadVisitor {
8380 public:
8381 explicit ActivationsFinder(JSFunction* function)
8382 : function_(function), has_activations_(false) {}
8383
8384 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8385 if (has_activations_) return;
8386
8387 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8388 JavaScriptFrame* frame = it.frame();
8389 if (frame->is_optimized() && frame->function() == function_) {
8390 has_activations_ = true;
8391 return;
8392 }
8393 }
8394 }
8395
8396 bool has_activations() { return has_activations_; }
8397
8398 private:
8399 JSFunction* function_;
8400 bool has_activations_;
8401};
8402
8403
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008404RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008405 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008406 ASSERT(args.length() == 1);
8407 RUNTIME_ASSERT(args[0]->IsSmi());
8408 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008409 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008410 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8411 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008412 int frames = deoptimizer->output_count();
8413
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008414 deoptimizer->MaterializeHeapNumbers();
8415 delete deoptimizer;
8416
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008417 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008418 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008419 for (int i = 0; i < frames - 1; i++) it.Advance();
8420 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008421
8422 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008423 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008424 Handle<Object> arguments;
8425 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008426 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008427 if (arguments.is_null()) {
8428 // FunctionGetArguments can't throw an exception, so cast away the
8429 // doubt with an assert.
8430 arguments = Handle<Object>(
8431 Accessors::FunctionGetArguments(*function,
8432 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008433 ASSERT(*arguments != isolate->heap()->null_value());
8434 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008435 }
8436 frame->SetExpression(i, *arguments);
8437 }
8438 }
8439
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008440 if (type == Deoptimizer::EAGER) {
8441 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008442 }
8443
8444 // Avoid doing too much work when running with --always-opt and keep
8445 // the optimized code around.
8446 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008447 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008448 }
8449
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008450 // Find other optimized activations of the function.
8451 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008452 while (!it.done()) {
8453 JavaScriptFrame* frame = it.frame();
8454 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008455 has_other_activations = true;
8456 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008457 }
8458 it.Advance();
8459 }
8460
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008461 if (!has_other_activations) {
8462 ActivationsFinder activations_finder(*function);
8463 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8464 has_other_activations = activations_finder.has_activations();
8465 }
8466
8467 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008468 if (FLAG_trace_deopt) {
8469 PrintF("[removing optimized code for: ");
8470 function->PrintName();
8471 PrintF("]\n");
8472 }
8473 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008474 } else {
8475 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008476 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008477 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008478}
8479
8480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008481RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008482 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008483 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008484 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008485}
8486
8487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008488RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008489 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008490 ASSERT(args.length() == 1);
8491 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008492 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008493
8494 Deoptimizer::DeoptimizeFunction(*function);
8495
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008496 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008497}
8498
8499
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008500RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8501#if defined(USE_SIMULATOR)
8502 return isolate->heap()->true_value();
8503#else
8504 return isolate->heap()->false_value();
8505#endif
8506}
8507
8508
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008509RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8510 HandleScope scope(isolate);
8511 ASSERT(args.length() == 1);
8512 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8513 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8514 function->MarkForLazyRecompilation();
8515 return isolate->heap()->undefined_value();
8516}
8517
8518
lrn@chromium.org1c092762011-05-09 09:42:16 +00008519RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8520 HandleScope scope(isolate);
8521 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008522 // The least significant bit (after untagging) indicates whether the
8523 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008524 if (!V8::UseCrankshaft()) {
8525 return Smi::FromInt(4); // 4 == "never".
8526 }
8527 if (FLAG_always_opt) {
8528 return Smi::FromInt(3); // 3 == "always".
8529 }
8530 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8531 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8532 : Smi::FromInt(2); // 2 == "no".
8533}
8534
8535
8536RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8537 HandleScope scope(isolate);
8538 ASSERT(args.length() == 1);
8539 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8540 return Smi::FromInt(function->shared()->opt_count());
8541}
8542
8543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008544RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008545 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008546 ASSERT(args.length() == 1);
8547 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8548
8549 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008550 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008551
8552 // We have hit a back edge in an unoptimized frame for a function that was
8553 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008554 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008555 // Keep track of whether we've succeeded in optimizing.
8556 bool succeeded = unoptimized->optimizable();
8557 if (succeeded) {
8558 // If we are trying to do OSR when there are already optimized
8559 // activations of the function, it means (a) the function is directly or
8560 // indirectly recursive and (b) an optimized invocation has been
8561 // deoptimized so that we are currently in an unoptimized activation.
8562 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008563 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008564 while (succeeded && !it.done()) {
8565 JavaScriptFrame* frame = it.frame();
8566 succeeded = !frame->is_optimized() || frame->function() != *function;
8567 it.Advance();
8568 }
8569 }
8570
8571 int ast_id = AstNode::kNoNumber;
8572 if (succeeded) {
8573 // The top JS function is this one, the PC is somewhere in the
8574 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008575 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008576 JavaScriptFrame* frame = it.frame();
8577 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008578 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008579 ASSERT(unoptimized->contains(frame->pc()));
8580
8581 // Use linear search of the unoptimized code's stack check table to find
8582 // the AST id matching the PC.
8583 Address start = unoptimized->instruction_start();
8584 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008585 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008586 uint32_t table_length = Memory::uint32_at(table_cursor);
8587 table_cursor += kIntSize;
8588 for (unsigned i = 0; i < table_length; ++i) {
8589 // Table entries are (AST id, pc offset) pairs.
8590 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8591 if (pc_offset == target_pc_offset) {
8592 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8593 break;
8594 }
8595 table_cursor += 2 * kIntSize;
8596 }
8597 ASSERT(ast_id != AstNode::kNoNumber);
8598 if (FLAG_trace_osr) {
8599 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8600 function->PrintName();
8601 PrintF("]\n");
8602 }
8603
8604 // Try to compile the optimized code. A true return value from
8605 // CompileOptimized means that compilation succeeded, not necessarily
8606 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008607 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008608 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008609 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8610 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008611 if (data->OsrPcOffset()->value() >= 0) {
8612 if (FLAG_trace_osr) {
8613 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008614 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008615 }
8616 ASSERT(data->OsrAstId()->value() == ast_id);
8617 } else {
8618 // We may never generate the desired OSR entry if we emit an
8619 // early deoptimize.
8620 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008621 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008622 } else {
8623 succeeded = false;
8624 }
8625 }
8626
8627 // Revert to the original stack checks in the original unoptimized code.
8628 if (FLAG_trace_osr) {
8629 PrintF("[restoring original stack checks in ");
8630 function->PrintName();
8631 PrintF("]\n");
8632 }
8633 StackCheckStub check_stub;
8634 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008635 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008636 Deoptimizer::RevertStackCheckCode(*unoptimized,
8637 *check_code,
8638 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008639
8640 // Allow OSR only at nesting level zero again.
8641 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8642
8643 // If the optimization attempt succeeded, return the AST id tagged as a
8644 // smi. This tells the builtin that we need to translate the unoptimized
8645 // frame to an optimized one.
8646 if (succeeded) {
8647 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8648 return Smi::FromInt(ast_id);
8649 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008650 if (function->IsMarkedForLazyRecompilation()) {
8651 function->ReplaceCode(function->shared()->code());
8652 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008653 return Smi::FromInt(-1);
8654 }
8655}
8656
8657
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008658RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8659 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8660 return isolate->heap()->undefined_value();
8661}
8662
8663
danno@chromium.orgc612e022011-11-10 11:38:15 +00008664RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8665 HandleScope scope(isolate);
8666 ASSERT(args.length() >= 2);
8667 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8668 Object* receiver = args[0];
8669 int argc = args.length() - 2;
8670
8671 // If there are too many arguments, allocate argv via malloc.
8672 const int argv_small_size = 10;
8673 Handle<Object> argv_small_buffer[argv_small_size];
8674 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8675 Handle<Object>* argv = argv_small_buffer;
8676 if (argc > argv_small_size) {
8677 argv = new Handle<Object>[argc];
8678 if (argv == NULL) return isolate->StackOverflow();
8679 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8680 }
8681
8682 for (int i = 0; i < argc; ++i) {
8683 MaybeObject* maybe = args[1 + i];
8684 Object* object;
8685 if (!maybe->To<Object>(&object)) return maybe;
8686 argv[i] = Handle<Object>(object);
8687 }
8688
8689 bool threw;
8690 Handle<JSReceiver> hfun(fun);
8691 Handle<Object> hreceiver(receiver);
8692 Handle<Object> result =
8693 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8694
8695 if (threw) return Failure::Exception();
8696 return *result;
8697}
8698
8699
lrn@chromium.org34e60782011-09-15 07:25:40 +00008700RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8701 HandleScope scope(isolate);
8702 ASSERT(args.length() == 5);
8703 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8704 Object* receiver = args[1];
8705 CONVERT_CHECKED(JSObject, arguments, args[2]);
8706 CONVERT_CHECKED(Smi, shift, args[3]);
8707 CONVERT_CHECKED(Smi, arity, args[4]);
8708
8709 int offset = shift->value();
8710 int argc = arity->value();
8711 ASSERT(offset >= 0);
8712 ASSERT(argc >= 0);
8713
8714 // If there are too many arguments, allocate argv via malloc.
8715 const int argv_small_size = 10;
8716 Handle<Object> argv_small_buffer[argv_small_size];
8717 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8718 Handle<Object>* argv = argv_small_buffer;
8719 if (argc > argv_small_size) {
8720 argv = new Handle<Object>[argc];
8721 if (argv == NULL) return isolate->StackOverflow();
8722 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8723 }
8724
8725 for (int i = 0; i < argc; ++i) {
8726 MaybeObject* maybe = arguments->GetElement(offset + i);
8727 Object* object;
8728 if (!maybe->To<Object>(&object)) return maybe;
8729 argv[i] = Handle<Object>(object);
8730 }
8731
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008732 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008733 Handle<JSReceiver> hfun(fun);
8734 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008735 Handle<Object> result =
8736 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008737
8738 if (threw) return Failure::Exception();
8739 return *result;
8740}
8741
8742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008743RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008744 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008745 ASSERT(args.length() == 1);
8746 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8747 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8748}
8749
8750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008751RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008752 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008753 ASSERT(args.length() == 1);
8754 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8755 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8756}
8757
8758
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008759RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008760 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008761 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008762
kasper.lund7276f142008-07-30 08:49:36 +00008763 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008764 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008765 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008766 { MaybeObject* maybe_result =
8767 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008768 if (!maybe_result->ToObject(&result)) return maybe_result;
8769 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008771 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008772
kasper.lund7276f142008-07-30 08:49:36 +00008773 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008774}
8775
lrn@chromium.org303ada72010-10-27 09:33:13 +00008776
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008777RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8778 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008779 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008780 JSObject* extension_object;
8781 if (args[0]->IsJSObject()) {
8782 extension_object = JSObject::cast(args[0]);
8783 } else {
8784 // Convert the object to a proper JavaScript object.
8785 MaybeObject* maybe_js_object = args[0]->ToObject();
8786 if (!maybe_js_object->To(&extension_object)) {
8787 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8788 HandleScope scope(isolate);
8789 Handle<Object> handle = args.at<Object>(0);
8790 Handle<Object> result =
8791 isolate->factory()->NewTypeError("with_expression",
8792 HandleVector(&handle, 1));
8793 return isolate->Throw(*result);
8794 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008795 return maybe_js_object;
8796 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008797 }
8798 }
8799
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008800 JSFunction* function;
8801 if (args[1]->IsSmi()) {
8802 // A smi sentinel indicates a context nested inside global code rather
8803 // than some function. There is a canonical empty function that can be
8804 // gotten from the global context.
8805 function = isolate->context()->global_context()->closure();
8806 } else {
8807 function = JSFunction::cast(args[1]);
8808 }
8809
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008810 Context* context;
8811 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008812 isolate->heap()->AllocateWithContext(function,
8813 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008814 extension_object);
8815 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008816 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008817 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008818}
8819
8820
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008821RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008822 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008823 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008824 String* name = String::cast(args[0]);
8825 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008826 JSFunction* function;
8827 if (args[2]->IsSmi()) {
8828 // A smi sentinel indicates a context nested inside global code rather
8829 // than some function. There is a canonical empty function that can be
8830 // gotten from the global context.
8831 function = isolate->context()->global_context()->closure();
8832 } else {
8833 function = JSFunction::cast(args[2]);
8834 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008835 Context* context;
8836 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008837 isolate->heap()->AllocateCatchContext(function,
8838 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008839 name,
8840 thrown_object);
8841 if (!maybe_context->To(&context)) return maybe_context;
8842 isolate->set_context(context);
8843 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008844}
8845
8846
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008847RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8848 NoHandleAllocation ha;
8849 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008850 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008851 JSFunction* function;
8852 if (args[1]->IsSmi()) {
8853 // A smi sentinel indicates a context nested inside global code rather
8854 // than some function. There is a canonical empty function that can be
8855 // gotten from the global context.
8856 function = isolate->context()->global_context()->closure();
8857 } else {
8858 function = JSFunction::cast(args[1]);
8859 }
8860 Context* context;
8861 MaybeObject* maybe_context =
8862 isolate->heap()->AllocateBlockContext(function,
8863 isolate->context(),
8864 scope_info);
8865 if (!maybe_context->To(&context)) return maybe_context;
8866 isolate->set_context(context);
8867 return context;
8868}
8869
8870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008871RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008872 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873 ASSERT(args.length() == 2);
8874
8875 CONVERT_ARG_CHECKED(Context, context, 0);
8876 CONVERT_ARG_CHECKED(String, name, 1);
8877
8878 int index;
8879 PropertyAttributes attributes;
8880 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008881 BindingFlags binding_flags;
8882 Handle<Object> holder = context->Lookup(name,
8883 flags,
8884 &index,
8885 &attributes,
8886 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008888 // If the slot was not found the result is true.
8889 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008890 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008891 }
8892
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008893 // If the slot was found in a context, it should be DONT_DELETE.
8894 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008895 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008896 }
8897
8898 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008899 // the global object, or the subject of a with. Try to delete it
8900 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008901 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008902 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008903}
8904
8905
ager@chromium.orga1645e22009-09-09 19:27:10 +00008906// A mechanism to return a pair of Object pointers in registers (if possible).
8907// How this is achieved is calling convention-dependent.
8908// All currently supported x86 compiles uses calling conventions that are cdecl
8909// variants where a 64-bit value is returned in two 32-bit registers
8910// (edx:eax on ia32, r1:r0 on ARM).
8911// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8912// In Win64 calling convention, a struct of two pointers is returned in memory,
8913// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008914#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008915struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008916 MaybeObject* x;
8917 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008918};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008919
lrn@chromium.org303ada72010-10-27 09:33:13 +00008920static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008921 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008922 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8923 // In Win64 they are assigned to a hidden first argument.
8924 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008925}
8926#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008927typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008928static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008929 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008930 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008931}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008932#endif
8933
8934
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008935static inline MaybeObject* Unhole(Heap* heap,
8936 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008937 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008938 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8939 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008940 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008941}
8942
8943
danno@chromium.org40cb8782011-05-25 07:58:50 +00008944static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8945 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008946 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008947 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008948 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008949 JSFunction* context_extension_function =
8950 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008951 // If the holder isn't a context extension object, we just return it
8952 // as the receiver. This allows arguments objects to be used as
8953 // receivers, but only if they are put in the context scope chain
8954 // explicitly via a with-statement.
8955 Object* constructor = holder->map()->constructor();
8956 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008957 // Fall back to using the global object as the implicit receiver if
8958 // the property turns out to be a local variable allocated in a
8959 // context extension object - introduced via eval. Implicit global
8960 // receivers are indicated with the hole value.
8961 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008962}
8963
8964
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008965static ObjectPair LoadContextSlotHelper(Arguments args,
8966 Isolate* isolate,
8967 bool throw_error) {
8968 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008969 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008971 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008972 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008975 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008976
8977 int index;
8978 PropertyAttributes attributes;
8979 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008980 BindingFlags binding_flags;
8981 Handle<Object> holder = context->Lookup(name,
8982 flags,
8983 &index,
8984 &attributes,
8985 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008986
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008987 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008988 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008989 ASSERT(holder->IsContext());
8990 // If the "property" we were looking for is a local variable, the
8991 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008992 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008993 // Use the hole as the receiver to signal that the receiver is implicit
8994 // and that the global receiver should be used (as distinguished from an
8995 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008996 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008997 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008998 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008999 switch (binding_flags) {
9000 case MUTABLE_CHECK_INITIALIZED:
9001 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9002 if (value->IsTheHole()) {
9003 Handle<Object> reference_error =
9004 isolate->factory()->NewReferenceError("not_defined",
9005 HandleVector(&name, 1));
9006 return MakePair(isolate->Throw(*reference_error), NULL);
9007 }
9008 // FALLTHROUGH
9009 case MUTABLE_IS_INITIALIZED:
9010 case IMMUTABLE_IS_INITIALIZED:
9011 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9012 ASSERT(!value->IsTheHole());
9013 return MakePair(value, *receiver);
9014 case IMMUTABLE_CHECK_INITIALIZED:
9015 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9016 case MISSING_BINDING:
9017 UNREACHABLE();
9018 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009020 }
9021
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009022 // Otherwise, if the slot was found the holder is a context extension
9023 // object, subject of a with, or a global object. We read the named
9024 // property from it.
9025 if (!holder.is_null()) {
9026 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9027 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009028 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009029 Handle<Object> receiver_handle(object->IsGlobalObject()
9030 ? GlobalObject::cast(*object)->global_receiver()
9031 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009032
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009033 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009034 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009035 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009036 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009037 }
9038
9039 if (throw_error) {
9040 // The property doesn't exist - throw exception.
9041 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009042 isolate->factory()->NewReferenceError("not_defined",
9043 HandleVector(&name, 1));
9044 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009045 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009046 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009047 return MakePair(isolate->heap()->undefined_value(),
9048 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009049 }
9050}
9051
9052
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009053RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009054 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009055}
9056
9057
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009058RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009059 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009060}
9061
9062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009063RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009064 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009065 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009066
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009067 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009069 CONVERT_ARG_CHECKED(String, name, 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009070 CONVERT_STRICT_MODE_ARG(strict_mode, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071
9072 int index;
9073 PropertyAttributes attributes;
9074 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009075 BindingFlags binding_flags;
9076 Handle<Object> holder = context->Lookup(name,
9077 flags,
9078 &index,
9079 &attributes,
9080 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009081
9082 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009083 // The property was found in a context slot.
9084 Handle<Context> context = Handle<Context>::cast(holder);
9085 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9086 context->get(index)->IsTheHole()) {
9087 Handle<Object> error =
9088 isolate->factory()->NewReferenceError("not_defined",
9089 HandleVector(&name, 1));
9090 return isolate->Throw(*error);
9091 }
9092 // Ignore if read_only variable.
9093 if ((attributes & READ_ONLY) == 0) {
9094 // Context is a fixed array and set cannot fail.
9095 context->set(index, *value);
9096 } else if (strict_mode == kStrictMode) {
9097 // Setting read only property in strict mode.
9098 Handle<Object> error =
9099 isolate->factory()->NewTypeError("strict_cannot_assign",
9100 HandleVector(&name, 1));
9101 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009102 }
9103 return *value;
9104 }
9105
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009106 // Slow case: The property is not in a context slot. It is either in a
9107 // context extension object, a property of the subject of a with, or a
9108 // property of the global object.
9109 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009110
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009111 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009112 // The property exists on the holder.
9113 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009114 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009115 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009116 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009117
9118 if (strict_mode == kStrictMode) {
9119 // Throw in strict mode (assignment to undefined variable).
9120 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009121 isolate->factory()->NewReferenceError(
9122 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009123 return isolate->Throw(*error);
9124 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009125 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009126 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009127 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009128 }
9129
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009130 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009131 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009132 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009133 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009134 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009135 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009136 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009137 // Setting read only property in strict mode.
9138 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009139 isolate->factory()->NewTypeError(
9140 "strict_cannot_assign", HandleVector(&name, 1));
9141 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142 }
9143 return *value;
9144}
9145
9146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009147RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009148 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009149 ASSERT(args.length() == 1);
9150
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009151 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009152}
9153
9154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009155RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009157 ASSERT(args.length() == 1);
9158
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009159 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009160}
9161
9162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009163RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009164 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009165 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009166}
9167
9168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009169RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 ASSERT(args.length() == 1);
9172
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009173 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009174 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009175 isolate->factory()->NewReferenceError("not_defined",
9176 HandleVector(&name, 1));
9177 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009178}
9179
9180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009181RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009182 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009183
9184 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009185 if (isolate->stack_guard()->IsStackOverflow()) {
9186 NoHandleAllocation na;
9187 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009188 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009189
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009190 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009191}
9192
9193
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009194static int StackSize() {
9195 int n = 0;
9196 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9197 return n;
9198}
9199
9200
9201static void PrintTransition(Object* result) {
9202 // indentation
9203 { const int nmax = 80;
9204 int n = StackSize();
9205 if (n <= nmax)
9206 PrintF("%4d:%*s", n, n, "");
9207 else
9208 PrintF("%4d:%*s", n, nmax, "...");
9209 }
9210
9211 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009212 JavaScriptFrame::PrintTop(stdout, true, false);
9213 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009214 } else {
9215 // function result
9216 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009217 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009218 PrintF("\n");
9219 }
9220}
9221
9222
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009223RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
9224 ASSERT(args.length() == 5);
9225 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9226 CONVERT_SMI_ARG_CHECKED(from_kind, 1);
9227 CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
9228 CONVERT_SMI_ARG_CHECKED(to_kind, 3);
9229 CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
9230 NoHandleAllocation ha;
9231 PrintF("*");
9232 obj->PrintElementsTransition(stdout,
9233 static_cast<ElementsKind>(from_kind), *from_elements,
9234 static_cast<ElementsKind>(to_kind), *to_elements);
9235 return isolate->heap()->undefined_value();
9236}
9237
9238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009239RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009240 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009241 NoHandleAllocation ha;
9242 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009243 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244}
9245
9246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009247RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009248 NoHandleAllocation ha;
9249 PrintTransition(args[0]);
9250 return args[0]; // return TOS
9251}
9252
9253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009254RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009255 NoHandleAllocation ha;
9256 ASSERT(args.length() == 1);
9257
9258#ifdef DEBUG
9259 if (args[0]->IsString()) {
9260 // If we have a string, assume it's a code "marker"
9261 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009262 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009263 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009264 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9265 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009266 } else {
9267 PrintF("DebugPrint: ");
9268 }
9269 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009270 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009271 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009272 HeapObject::cast(args[0])->map()->Print();
9273 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009274#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009275 // ShortPrint is available in release mode. Print is not.
9276 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277#endif
9278 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009279 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009280
9281 return args[0]; // return TOS
9282}
9283
9284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009285RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009286 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009287 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009288 isolate->PrintStack();
9289 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290}
9291
9292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009293RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009294 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009295 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009296
9297 // According to ECMA-262, section 15.9.1, page 117, the precision of
9298 // the number in a Date object representing a particular instant in
9299 // time is milliseconds. Therefore, we floor the result of getting
9300 // the OS time.
9301 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009302 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009303}
9304
9305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009306RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009307 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009308 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009309
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009310 CONVERT_ARG_CHECKED(String, str, 0);
9311 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009313 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009314
9315 MaybeObject* maybe_result_array =
9316 output->EnsureCanContainNonSmiElements();
9317 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009318 RUNTIME_ASSERT(output->HasFastElements());
9319
9320 AssertNoAllocation no_allocation;
9321
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009322 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009323 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9324 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009325 String::FlatContent str_content = str->GetFlatContent();
9326 if (str_content.IsAscii()) {
9327 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009328 output_array,
9329 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009330 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009331 ASSERT(str_content.IsTwoByte());
9332 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009333 output_array,
9334 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009335 }
9336
9337 if (result) {
9338 return *output;
9339 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009340 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341 }
9342}
9343
9344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009345RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009346 NoHandleAllocation ha;
9347 ASSERT(args.length() == 1);
9348
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009349 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009350 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009351 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009352}
9353
9354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009355RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009356 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009357 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009358
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009359 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009360}
9361
9362
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009363RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364 NoHandleAllocation ha;
9365 ASSERT(args.length() == 1);
9366
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009367 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009368 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009369}
9370
9371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009372RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009373 ASSERT(args.length() == 1);
9374 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009375 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009376 return JSGlobalObject::cast(global)->global_receiver();
9377}
9378
9379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009380RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009381 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009382 ASSERT_EQ(1, args.length());
9383 CONVERT_ARG_CHECKED(String, source, 0);
9384
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009385 source = Handle<String>(source->TryFlattenGetString());
9386 // Optimized fast case where we only have ascii characters.
9387 Handle<Object> result;
9388 if (source->IsSeqAsciiString()) {
9389 result = JsonParser<true>::Parse(source);
9390 } else {
9391 result = JsonParser<false>::Parse(source);
9392 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009393 if (result.is_null()) {
9394 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009395 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009396 return Failure::Exception();
9397 }
9398 return *result;
9399}
9400
9401
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009402bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9403 Handle<Context> context) {
9404 if (context->allow_code_gen_from_strings()->IsFalse()) {
9405 // Check with callback if set.
9406 AllowCodeGenerationFromStringsCallback callback =
9407 isolate->allow_code_gen_callback();
9408 if (callback == NULL) {
9409 // No callback set and code generation disallowed.
9410 return false;
9411 } else {
9412 // Callback set. Let it decide if code generation is allowed.
9413 VMState state(isolate, EXTERNAL);
9414 return callback(v8::Utils::ToLocal(context));
9415 }
9416 }
9417 return true;
9418}
9419
9420
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009421RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009422 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009423 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009424 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009425
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009426 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009427 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009428
9429 // Check if global context allows code generation from
9430 // strings. Throw an exception if it doesn't.
9431 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9432 return isolate->Throw(*isolate->factory()->NewError(
9433 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9434 }
9435
9436 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009437 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9438 source, context, true, kNonStrictMode, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009439 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009440 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009441 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9442 context,
9443 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009444 return *fun;
9445}
9446
9447
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009448static ObjectPair CompileGlobalEval(Isolate* isolate,
9449 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009450 Handle<Object> receiver,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009451 StrictModeFlag strict_mode,
9452 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009453 Handle<Context> context = Handle<Context>(isolate->context());
9454 Handle<Context> global_context = Handle<Context>(context->global_context());
9455
9456 // Check if global context allows code generation from
9457 // strings. Throw an exception if it doesn't.
9458 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9459 isolate->Throw(*isolate->factory()->NewError(
9460 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9461 return MakePair(Failure::Exception(), NULL);
9462 }
9463
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009464 // Deal with a normal eval call with a string argument. Compile it
9465 // and return the compiled function bound in the local context.
9466 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9467 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009468 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009469 context->IsGlobalContext(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009470 strict_mode,
9471 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009472 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009473 Handle<JSFunction> compiled =
9474 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009475 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009476 return MakePair(*compiled, *receiver);
9477}
9478
9479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009480RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009481 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009482
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009483 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009484 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009485
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009486 // If "eval" didn't refer to the original GlobalEval, it's not a
9487 // direct call to eval.
9488 // (And even if it is, but the first argument isn't a string, just let
9489 // execution default to an indirect call to eval, which will also return
9490 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009491 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009492 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009493 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009494 }
9495
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009496 CONVERT_STRICT_MODE_ARG(strict_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009497 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009498 return CompileGlobalEval(isolate,
9499 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009500 args.at<Object>(2),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009501 strict_mode,
9502 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009503}
9504
9505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009506RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009507 // This utility adjusts the property attributes for newly created Function
9508 // object ("new Function(...)") by changing the map.
9509 // All it does is changing the prototype property to enumerable
9510 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009511 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009512 ASSERT(args.length() == 1);
9513 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009514
9515 Handle<Map> map = func->shared()->strict_mode()
9516 ? isolate->strict_mode_function_instance_map()
9517 : isolate->function_instance_map();
9518
9519 ASSERT(func->map()->instance_type() == map->instance_type());
9520 ASSERT(func->map()->instance_size() == map->instance_size());
9521 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009522 return *func;
9523}
9524
9525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009526RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009527 // Allocate a block of memory in NewSpace (filled with a filler).
9528 // Use as fallback for allocation in generated code when NewSpace
9529 // is full.
9530 ASSERT(args.length() == 1);
9531 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9532 int size = size_smi->value();
9533 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9534 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009535 Heap* heap = isolate->heap();
9536 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009537 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009538 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009539 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009540 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009541 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009542 }
9543 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009544 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009545}
9546
9547
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009548// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009549// array. Returns true if the element was pushed on the stack and
9550// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009551RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009552 ASSERT(args.length() == 2);
9553 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009554 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009555 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009556 int length = Smi::cast(array->length())->value();
9557 FixedArray* elements = FixedArray::cast(array->elements());
9558 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009559 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009560 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009561 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009562 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009563 { MaybeObject* maybe_obj =
9564 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009565 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9566 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009567 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009568}
9569
9570
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009571/**
9572 * A simple visitor visits every element of Array's.
9573 * The backend storage can be a fixed array for fast elements case,
9574 * or a dictionary for sparse array. Since Dictionary is a subtype
9575 * of FixedArray, the class can be used by both fast and slow cases.
9576 * The second parameter of the constructor, fast_elements, specifies
9577 * whether the storage is a FixedArray or Dictionary.
9578 *
9579 * An index limit is used to deal with the situation that a result array
9580 * length overflows 32-bit non-negative integer.
9581 */
9582class ArrayConcatVisitor {
9583 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009584 ArrayConcatVisitor(Isolate* isolate,
9585 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009586 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009587 isolate_(isolate),
9588 storage_(Handle<FixedArray>::cast(
9589 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009590 index_offset_(0u),
9591 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009592
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009593 ~ArrayConcatVisitor() {
9594 clear_storage();
9595 }
9596
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009597 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009598 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009599 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009600
9601 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009602 if (index < static_cast<uint32_t>(storage_->length())) {
9603 storage_->set(index, *elm);
9604 return;
9605 }
9606 // Our initial estimate of length was foiled, possibly by
9607 // getters on the arrays increasing the length of later arrays
9608 // during iteration.
9609 // This shouldn't happen in anything but pathological cases.
9610 SetDictionaryMode(index);
9611 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009612 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009613 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009614 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009615 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009616 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009617 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009618 // Dictionary needed to grow.
9619 clear_storage();
9620 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009621 }
9622}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009623
9624 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009625 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9626 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009627 } else {
9628 index_offset_ += delta;
9629 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009630 }
9631
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009632 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009633 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009634 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009635 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009636 Handle<Map> map;
9637 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009638 map = isolate_->factory()->GetElementsTransitionMap(array,
9639 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009640 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009641 map = isolate_->factory()->GetElementsTransitionMap(array,
9642 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009643 }
9644 array->set_map(*map);
9645 array->set_length(*length);
9646 array->set_elements(*storage_);
9647 return array;
9648 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009649
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009650 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009651 // Convert storage to dictionary mode.
9652 void SetDictionaryMode(uint32_t index) {
9653 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009654 Handle<FixedArray> current_storage(*storage_);
9655 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009656 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9658 for (uint32_t i = 0; i < current_length; i++) {
9659 HandleScope loop_scope;
9660 Handle<Object> element(current_storage->get(i));
9661 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009662 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009663 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009664 if (!new_storage.is_identical_to(slow_storage)) {
9665 slow_storage = loop_scope.CloseAndEscape(new_storage);
9666 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009667 }
9668 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009669 clear_storage();
9670 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009671 fast_elements_ = false;
9672 }
9673
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009674 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009675 isolate_->global_handles()->Destroy(
9676 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009677 }
9678
9679 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009680 storage_ = Handle<FixedArray>::cast(
9681 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009682 }
9683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009684 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009685 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009686 // Index after last seen index. Always less than or equal to
9687 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009688 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009689 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009690};
9691
9692
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009693static uint32_t EstimateElementCount(Handle<JSArray> array) {
9694 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9695 int element_count = 0;
9696 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009697 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009698 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009699 // Fast elements can't have lengths that are not representable by
9700 // a 32-bit signed integer.
9701 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9702 int fast_length = static_cast<int>(length);
9703 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9704 for (int i = 0; i < fast_length; i++) {
9705 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009706 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009707 break;
9708 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009709 case FAST_DOUBLE_ELEMENTS:
9710 // TODO(1810): Decide if it's worthwhile to implement this.
9711 UNREACHABLE();
9712 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009713 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009714 Handle<NumberDictionary> dictionary(
9715 NumberDictionary::cast(array->elements()));
9716 int capacity = dictionary->Capacity();
9717 for (int i = 0; i < capacity; i++) {
9718 Handle<Object> key(dictionary->KeyAt(i));
9719 if (dictionary->IsKey(*key)) {
9720 element_count++;
9721 }
9722 }
9723 break;
9724 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009725 case NON_STRICT_ARGUMENTS_ELEMENTS:
9726 case EXTERNAL_BYTE_ELEMENTS:
9727 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9728 case EXTERNAL_SHORT_ELEMENTS:
9729 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9730 case EXTERNAL_INT_ELEMENTS:
9731 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9732 case EXTERNAL_FLOAT_ELEMENTS:
9733 case EXTERNAL_DOUBLE_ELEMENTS:
9734 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009735 // External arrays are always dense.
9736 return length;
9737 }
9738 // As an estimate, we assume that the prototype doesn't contain any
9739 // inherited elements.
9740 return element_count;
9741}
9742
9743
9744
9745template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009746static void IterateExternalArrayElements(Isolate* isolate,
9747 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009748 bool elements_are_ints,
9749 bool elements_are_guaranteed_smis,
9750 ArrayConcatVisitor* visitor) {
9751 Handle<ExternalArrayClass> array(
9752 ExternalArrayClass::cast(receiver->elements()));
9753 uint32_t len = static_cast<uint32_t>(array->length());
9754
9755 ASSERT(visitor != NULL);
9756 if (elements_are_ints) {
9757 if (elements_are_guaranteed_smis) {
9758 for (uint32_t j = 0; j < len; j++) {
9759 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009760 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009761 visitor->visit(j, e);
9762 }
9763 } else {
9764 for (uint32_t j = 0; j < len; j++) {
9765 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009766 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009767 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9768 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9769 visitor->visit(j, e);
9770 } else {
9771 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009772 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009773 visitor->visit(j, e);
9774 }
9775 }
9776 }
9777 } else {
9778 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009779 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009780 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009781 visitor->visit(j, e);
9782 }
9783 }
9784}
9785
9786
9787// Used for sorting indices in a List<uint32_t>.
9788static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9789 uint32_t a = *ap;
9790 uint32_t b = *bp;
9791 return (a == b) ? 0 : (a < b) ? -1 : 1;
9792}
9793
9794
9795static void CollectElementIndices(Handle<JSObject> object,
9796 uint32_t range,
9797 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009798 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009799 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009800 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009801 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009802 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9803 uint32_t length = static_cast<uint32_t>(elements->length());
9804 if (range < length) length = range;
9805 for (uint32_t i = 0; i < length; i++) {
9806 if (!elements->get(i)->IsTheHole()) {
9807 indices->Add(i);
9808 }
9809 }
9810 break;
9811 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009812 case FAST_DOUBLE_ELEMENTS: {
9813 // TODO(1810): Decide if it's worthwhile to implement this.
9814 UNREACHABLE();
9815 break;
9816 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009817 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009818 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009819 uint32_t capacity = dict->Capacity();
9820 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009821 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009822 Handle<Object> k(dict->KeyAt(j));
9823 if (dict->IsKey(*k)) {
9824 ASSERT(k->IsNumber());
9825 uint32_t index = static_cast<uint32_t>(k->Number());
9826 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009827 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009828 }
9829 }
9830 }
9831 break;
9832 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009833 default: {
9834 int dense_elements_length;
9835 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009836 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009837 dense_elements_length =
9838 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009839 break;
9840 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009841 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009842 dense_elements_length =
9843 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009844 break;
9845 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009846 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009847 dense_elements_length =
9848 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009849 break;
9850 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009851 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009852 dense_elements_length =
9853 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009854 break;
9855 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009856 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009857 dense_elements_length =
9858 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009859 break;
9860 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009861 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009862 dense_elements_length =
9863 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009864 break;
9865 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009866 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009867 dense_elements_length =
9868 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009869 break;
9870 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009871 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009872 dense_elements_length =
9873 ExternalFloatArray::cast(object->elements())->length();
9874 break;
9875 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009876 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009877 dense_elements_length =
9878 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009879 break;
9880 }
9881 default:
9882 UNREACHABLE();
9883 dense_elements_length = 0;
9884 break;
9885 }
9886 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9887 if (range <= length) {
9888 length = range;
9889 // We will add all indices, so we might as well clear it first
9890 // and avoid duplicates.
9891 indices->Clear();
9892 }
9893 for (uint32_t i = 0; i < length; i++) {
9894 indices->Add(i);
9895 }
9896 if (length == range) return; // All indices accounted for already.
9897 break;
9898 }
9899 }
9900
9901 Handle<Object> prototype(object->GetPrototype());
9902 if (prototype->IsJSObject()) {
9903 // The prototype will usually have no inherited element indices,
9904 // but we have to check.
9905 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9906 }
9907}
9908
9909
9910/**
9911 * A helper function that visits elements of a JSArray in numerical
9912 * order.
9913 *
9914 * The visitor argument called for each existing element in the array
9915 * with the element index and the element's value.
9916 * Afterwards it increments the base-index of the visitor by the array
9917 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009918 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009919 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009920static bool IterateElements(Isolate* isolate,
9921 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009922 ArrayConcatVisitor* visitor) {
9923 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9924 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009925 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009926 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009927 // Run through the elements FixedArray and use HasElement and GetElement
9928 // to check the prototype for missing elements.
9929 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9930 int fast_length = static_cast<int>(length);
9931 ASSERT(fast_length <= elements->length());
9932 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009933 HandleScope loop_scope(isolate);
9934 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009935 if (!element_value->IsTheHole()) {
9936 visitor->visit(j, element_value);
9937 } else if (receiver->HasElement(j)) {
9938 // Call GetElement on receiver, not its prototype, or getters won't
9939 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009940 element_value = Object::GetElement(receiver, j);
9941 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009942 visitor->visit(j, element_value);
9943 }
9944 }
9945 break;
9946 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009947 case FAST_DOUBLE_ELEMENTS: {
9948 // TODO(1810): Decide if it's worthwhile to implement this.
9949 UNREACHABLE();
9950 break;
9951 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009952 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009953 Handle<NumberDictionary> dict(receiver->element_dictionary());
9954 List<uint32_t> indices(dict->Capacity() / 2);
9955 // Collect all indices in the object and the prototypes less
9956 // than length. This might introduce duplicates in the indices list.
9957 CollectElementIndices(receiver, length, &indices);
9958 indices.Sort(&compareUInt32);
9959 int j = 0;
9960 int n = indices.length();
9961 while (j < n) {
9962 HandleScope loop_scope;
9963 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009964 Handle<Object> element = Object::GetElement(receiver, index);
9965 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009966 visitor->visit(index, element);
9967 // Skip to next different index (i.e., omit duplicates).
9968 do {
9969 j++;
9970 } while (j < n && indices[j] == index);
9971 }
9972 break;
9973 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009974 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009975 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9976 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009977 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009978 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009979 visitor->visit(j, e);
9980 }
9981 break;
9982 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009983 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009984 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009985 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009986 break;
9987 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009988 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009989 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009990 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009991 break;
9992 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009993 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009994 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009996 break;
9997 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009998 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009999 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010000 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010001 break;
10002 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010003 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010004 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010005 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010006 break;
10007 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010008 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010009 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010010 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010011 break;
10012 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010013 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010014 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010015 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010016 break;
10017 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010018 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010019 IterateExternalArrayElements<ExternalDoubleArray, double>(
10020 isolate, receiver, false, false, visitor);
10021 break;
10022 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010023 default:
10024 UNREACHABLE();
10025 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010026 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010027 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010028 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010029}
10030
10031
10032/**
10033 * Array::concat implementation.
10034 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010035 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010036 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010037 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010038RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010039 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010040 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010041
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10043 int argument_count = static_cast<int>(arguments->length()->Number());
10044 RUNTIME_ASSERT(arguments->HasFastElements());
10045 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010046
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010047 // Pass 1: estimate the length and number of elements of the result.
10048 // The actual length can be larger if any of the arguments have getters
10049 // that mutate other arguments (but will otherwise be precise).
10050 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010051
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010052 uint32_t estimate_result_length = 0;
10053 uint32_t estimate_nof_elements = 0;
10054 {
10055 for (int i = 0; i < argument_count; i++) {
10056 HandleScope loop_scope;
10057 Handle<Object> obj(elements->get(i));
10058 uint32_t length_estimate;
10059 uint32_t element_estimate;
10060 if (obj->IsJSArray()) {
10061 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010062 // TODO(1810): Find out if it's worthwhile to properly support
10063 // arbitrary ElementsKinds. For now, pessimistically transition to
10064 // FAST_ELEMENTS.
10065 if (array->HasFastDoubleElements()) {
10066 array = Handle<JSArray>::cast(
10067 TransitionElementsKind(array, FAST_ELEMENTS));
10068 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010069 length_estimate =
10070 static_cast<uint32_t>(array->length()->Number());
10071 element_estimate =
10072 EstimateElementCount(array);
10073 } else {
10074 length_estimate = 1;
10075 element_estimate = 1;
10076 }
10077 // Avoid overflows by capping at kMaxElementCount.
10078 if (JSObject::kMaxElementCount - estimate_result_length <
10079 length_estimate) {
10080 estimate_result_length = JSObject::kMaxElementCount;
10081 } else {
10082 estimate_result_length += length_estimate;
10083 }
10084 if (JSObject::kMaxElementCount - estimate_nof_elements <
10085 element_estimate) {
10086 estimate_nof_elements = JSObject::kMaxElementCount;
10087 } else {
10088 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010089 }
10090 }
10091 }
10092
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010093 // If estimated number of elements is more than half of length, a
10094 // fixed array (fast case) is more time and space-efficient than a
10095 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010096 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010097
10098 Handle<FixedArray> storage;
10099 if (fast_case) {
10100 // The backing storage array must have non-existing elements to
10101 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 storage = isolate->factory()->NewFixedArrayWithHoles(
10103 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010104 } else {
10105 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10106 uint32_t at_least_space_for = estimate_nof_elements +
10107 (estimate_nof_elements >> 2);
10108 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010109 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010110 }
10111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010112 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010113
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010114 for (int i = 0; i < argument_count; i++) {
10115 Handle<Object> obj(elements->get(i));
10116 if (obj->IsJSArray()) {
10117 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010118 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010119 return Failure::Exception();
10120 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010121 } else {
10122 visitor.visit(0, obj);
10123 visitor.increase_index_offset(1);
10124 }
10125 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010126
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010127 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010128}
10129
10130
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010131// This will not allocate (flatten the string), but it may run
10132// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010133RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010134 NoHandleAllocation ha;
10135 ASSERT(args.length() == 1);
10136
10137 CONVERT_CHECKED(String, string, args[0]);
10138 StringInputBuffer buffer(string);
10139 while (buffer.has_more()) {
10140 uint16_t character = buffer.GetNext();
10141 PrintF("%c", character);
10142 }
10143 return string;
10144}
10145
ager@chromium.org5ec48922009-05-05 07:25:34 +000010146// Moves all own elements of an object, that are below a limit, to positions
10147// starting at zero. All undefined values are placed after non-undefined values,
10148// and are followed by non-existing element. Does not change the length
10149// property.
10150// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010151RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010152 ASSERT(args.length() == 2);
10153 CONVERT_CHECKED(JSObject, object, args[0]);
10154 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10155 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010156}
10157
10158
10159// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010160RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010161 ASSERT(args.length() == 2);
10162 CONVERT_CHECKED(JSArray, from, args[0]);
10163 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010164 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010165 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010166 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010167 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10168 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010169 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010170 } else if (new_elements->map() ==
10171 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010172 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010173 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010174 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010175 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010176 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010177 Object* new_map;
10178 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010179 to->set_map(Map::cast(new_map));
10180 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010181 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010182 Object* obj;
10183 { MaybeObject* maybe_obj = from->ResetElements();
10184 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10185 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010186 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010187 return to;
10188}
10189
10190
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010191// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010192RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010193 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010194 CONVERT_CHECKED(JSObject, object, args[0]);
10195 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010196 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010197 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010198 } else if (object->IsJSArray()) {
10199 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010201 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010202 }
10203}
10204
10205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010206RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010207 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010208
10209 ASSERT_EQ(3, args.length());
10210
ager@chromium.orgac091b72010-05-05 07:34:42 +000010211 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010212 Handle<Object> key1 = args.at<Object>(1);
10213 Handle<Object> key2 = args.at<Object>(2);
10214
10215 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010216 if (!key1->ToArrayIndex(&index1)
10217 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010218 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010219 }
10220
ager@chromium.orgac091b72010-05-05 07:34:42 +000010221 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010222 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010223 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010224 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010225 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010227 RETURN_IF_EMPTY_HANDLE(isolate,
10228 SetElement(jsobject, index1, tmp2, kStrictMode));
10229 RETURN_IF_EMPTY_HANDLE(isolate,
10230 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010231
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010233}
10234
10235
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010236// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010237// might have elements. Can either return keys (positive integers) or
10238// intervals (pair of a negative integer (-start-1) followed by a
10239// positive (length)) or undefined values.
10240// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010241RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010243 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010244 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010246 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010247 // Create an array and get all the keys into it, then remove all the
10248 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010249 bool threw = false;
10250 Handle<FixedArray> keys =
10251 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10252 if (threw) return Failure::Exception();
10253
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 int keys_length = keys->length();
10255 for (int i = 0; i < keys_length; i++) {
10256 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010257 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010258 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259 // Zap invalid keys.
10260 keys->set_undefined(i);
10261 }
10262 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010263 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010265 ASSERT(array->HasFastElements() ||
10266 array->HasFastSmiOnlyElements() ||
10267 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010268 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010270 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010271 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010272 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010273 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010274 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010276 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010278 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010279 }
10280}
10281
10282
10283// DefineAccessor takes an optional final argument which is the
10284// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10285// to the way accessors are implemented, it is set for both the getter
10286// and setter on the first call to DefineAccessor and ignored on
10287// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010288RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010289 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10290 // Compute attributes.
10291 PropertyAttributes attributes = NONE;
10292 if (args.length() == 5) {
10293 CONVERT_CHECKED(Smi, attrs, args[4]);
10294 int value = attrs->value();
10295 // Only attribute bits should be set.
10296 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10297 attributes = static_cast<PropertyAttributes>(value);
10298 }
10299
10300 CONVERT_CHECKED(JSObject, obj, args[0]);
10301 CONVERT_CHECKED(String, name, args[1]);
10302 CONVERT_CHECKED(Smi, flag, args[2]);
10303 CONVERT_CHECKED(JSFunction, fun, args[3]);
10304 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10305}
10306
10307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010308RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309 ASSERT(args.length() == 3);
10310 CONVERT_CHECKED(JSObject, obj, args[0]);
10311 CONVERT_CHECKED(String, name, args[1]);
10312 CONVERT_CHECKED(Smi, flag, args[2]);
10313 return obj->LookupAccessor(name, flag->value() == 0);
10314}
10315
10316
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010317#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010318RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010319 ASSERT(args.length() == 0);
10320 return Execution::DebugBreakHelper();
10321}
10322
10323
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324// Helper functions for wrapping and unwrapping stack frame ids.
10325static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010326 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327 return Smi::FromInt(id >> 2);
10328}
10329
10330
10331static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10332 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10333}
10334
10335
10336// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010337// args[0]: debug event listener function to set or null or undefined for
10338// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010339// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010340RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010342 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10343 args[0]->IsUndefined() ||
10344 args[0]->IsNull());
10345 Handle<Object> callback = args.at<Object>(0);
10346 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010347 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010349 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350}
10351
10352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010353RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010354 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 isolate->stack_guard()->DebugBreak();
10356 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010357}
10358
10359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010360static MaybeObject* DebugLookupResultValue(Heap* heap,
10361 Object* receiver,
10362 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010363 LookupResult* result,
10364 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010365 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010366 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010367 case NORMAL:
10368 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010369 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010370 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010371 }
10372 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010373 case FIELD:
10374 value =
10375 JSObject::cast(
10376 result->holder())->FastPropertyAt(result->GetFieldIndex());
10377 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010378 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010379 }
10380 return value;
10381 case CONSTANT_FUNCTION:
10382 return result->GetConstantFunction();
10383 case CALLBACKS: {
10384 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010385 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010386 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10387 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010388 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010389 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010390 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010391 maybe_value = heap->isolate()->pending_exception();
10392 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010393 if (caught_exception != NULL) {
10394 *caught_exception = true;
10395 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010396 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010397 }
10398 return value;
10399 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010400 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010401 }
10402 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010403 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010404 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010405 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010406 case CONSTANT_TRANSITION:
10407 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010408 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010409 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010410 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010411 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010412 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010413 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010414 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010415}
10416
10417
ager@chromium.org32912102009-01-16 10:38:43 +000010418// Get debugger related details for an object property.
10419// args[0]: object holding property
10420// args[1]: name of the property
10421//
10422// The array returned contains the following information:
10423// 0: Property value
10424// 1: Property details
10425// 2: Property value is exception
10426// 3: Getter function if defined
10427// 4: Setter function if defined
10428// Items 2-4 are only filled if the property has either a getter or a setter
10429// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010430RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010431 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010432
10433 ASSERT(args.length() == 2);
10434
10435 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10436 CONVERT_ARG_CHECKED(String, name, 1);
10437
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010438 // Make sure to set the current context to the context before the debugger was
10439 // entered (if the debugger is entered). The reason for switching context here
10440 // is that for some property lookups (accessors and interceptors) callbacks
10441 // into the embedding application can occour, and the embedding application
10442 // could have the assumption that its own global context is the current
10443 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010444 SaveContext save(isolate);
10445 if (isolate->debug()->InDebugger()) {
10446 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010447 }
10448
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010449 // Skip the global proxy as it has no properties and always delegates to the
10450 // real global object.
10451 if (obj->IsJSGlobalProxy()) {
10452 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10453 }
10454
10455
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010456 // Check if the name is trivially convertible to an index and get the element
10457 // if so.
10458 uint32_t index;
10459 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010460 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010461 Object* element_or_char;
10462 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010463 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010464 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10465 return maybe_element_or_char;
10466 }
10467 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010468 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010469 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010470 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471 }
10472
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010473 // Find the number of objects making up this.
10474 int length = LocalPrototypeChainLength(*obj);
10475
10476 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010477 Handle<JSObject> jsproto = obj;
10478 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010479 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010480 jsproto->LocalLookup(*name, &result);
10481 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010482 // LookupResult is not GC safe as it holds raw object pointers.
10483 // GC can happen later in this code so put the required fields into
10484 // local variables using handles when required for later use.
10485 PropertyType result_type = result.type();
10486 Handle<Object> result_callback_obj;
10487 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010488 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10489 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010490 }
10491 Smi* property_details = result.GetPropertyDetails().AsSmi();
10492 // DebugLookupResultValue can cause GC so details from LookupResult needs
10493 // to be copied to handles before this.
10494 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010495 Object* raw_value;
10496 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010497 DebugLookupResultValue(isolate->heap(), *obj, *name,
10498 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010499 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10500 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010501 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010502
10503 // If the callback object is a fixed array then it contains JavaScript
10504 // getter and/or setter.
10505 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10506 result_callback_obj->IsFixedArray();
10507 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010508 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010509 details->set(0, *value);
10510 details->set(1, property_details);
10511 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010512 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010513 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10514 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10515 }
10516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010517 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010518 }
10519 if (i < length - 1) {
10520 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10521 }
10522 }
10523
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010524 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010525}
10526
10527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010528RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010529 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530
10531 ASSERT(args.length() == 2);
10532
10533 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10534 CONVERT_ARG_CHECKED(String, name, 1);
10535
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010536 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010537 obj->Lookup(*name, &result);
10538 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010539 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010540 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010541 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542}
10543
10544
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010545// Return the property type calculated from the property details.
10546// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010547RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010548 ASSERT(args.length() == 1);
10549 CONVERT_CHECKED(Smi, details, args[0]);
10550 PropertyType type = PropertyDetails(details).type();
10551 return Smi::FromInt(static_cast<int>(type));
10552}
10553
10554
10555// Return the property attribute calculated from the property details.
10556// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010557RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010558 ASSERT(args.length() == 1);
10559 CONVERT_CHECKED(Smi, details, args[0]);
10560 PropertyAttributes attributes = PropertyDetails(details).attributes();
10561 return Smi::FromInt(static_cast<int>(attributes));
10562}
10563
10564
10565// Return the property insertion index calculated from the property details.
10566// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010567RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010568 ASSERT(args.length() == 1);
10569 CONVERT_CHECKED(Smi, details, args[0]);
10570 int index = PropertyDetails(details).index();
10571 return Smi::FromInt(index);
10572}
10573
10574
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575// Return property value from named interceptor.
10576// args[0]: object
10577// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010578RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010579 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010580 ASSERT(args.length() == 2);
10581 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10582 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10583 CONVERT_ARG_CHECKED(String, name, 1);
10584
10585 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010586 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587}
10588
10589
10590// Return element value from indexed interceptor.
10591// args[0]: object
10592// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010593RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010594 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010595 ASSERT(args.length() == 2);
10596 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10597 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10598 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10599
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010600 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601}
10602
10603
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010604RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010605 ASSERT(args.length() >= 1);
10606 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010607 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010608 if (isolate->debug()->break_id() == 0 ||
10609 break_id != isolate->debug()->break_id()) {
10610 return isolate->Throw(
10611 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612 }
10613
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010614 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615}
10616
10617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010618RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010619 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010620 ASSERT(args.length() == 1);
10621
10622 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010623 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010624 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10625 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010626 if (!maybe_result->ToObject(&result)) return maybe_result;
10627 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010628
10629 // Count all frames which are relevant to debugging stack trace.
10630 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010631 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010632 if (id == StackFrame::NO_ID) {
10633 // If there is no JavaScript stack frame count is 0.
10634 return Smi::FromInt(0);
10635 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010636
10637 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10638 n += it.frame()->GetInlineCount();
10639 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010640 return Smi::FromInt(n);
10641}
10642
10643
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010644class FrameInspector {
10645 public:
10646 FrameInspector(JavaScriptFrame* frame,
10647 int inlined_frame_index,
10648 Isolate* isolate)
10649 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10650 // Calculate the deoptimized frame.
10651 if (frame->is_optimized()) {
10652 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10653 frame, inlined_frame_index, isolate);
10654 }
10655 has_adapted_arguments_ = frame_->has_adapted_arguments();
10656 is_optimized_ = frame_->is_optimized();
10657 }
10658
10659 ~FrameInspector() {
10660 // Get rid of the calculated deoptimized frame if any.
10661 if (deoptimized_frame_ != NULL) {
10662 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10663 isolate_);
10664 }
10665 }
10666
10667 int GetParametersCount() {
10668 return is_optimized_
10669 ? deoptimized_frame_->parameters_count()
10670 : frame_->ComputeParametersCount();
10671 }
10672 int expression_count() { return deoptimized_frame_->expression_count(); }
10673 Object* GetFunction() {
10674 return is_optimized_
10675 ? deoptimized_frame_->GetFunction()
10676 : frame_->function();
10677 }
10678 Object* GetParameter(int index) {
10679 return is_optimized_
10680 ? deoptimized_frame_->GetParameter(index)
10681 : frame_->GetParameter(index);
10682 }
10683 Object* GetExpression(int index) {
10684 return is_optimized_
10685 ? deoptimized_frame_->GetExpression(index)
10686 : frame_->GetExpression(index);
10687 }
10688
10689 // To inspect all the provided arguments the frame might need to be
10690 // replaced with the arguments frame.
10691 void SetArgumentsFrame(JavaScriptFrame* frame) {
10692 ASSERT(has_adapted_arguments_);
10693 frame_ = frame;
10694 is_optimized_ = frame_->is_optimized();
10695 ASSERT(!is_optimized_);
10696 }
10697
10698 private:
10699 JavaScriptFrame* frame_;
10700 DeoptimizedFrameInfo* deoptimized_frame_;
10701 Isolate* isolate_;
10702 bool is_optimized_;
10703 bool has_adapted_arguments_;
10704
10705 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10706};
10707
10708
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010709static const int kFrameDetailsFrameIdIndex = 0;
10710static const int kFrameDetailsReceiverIndex = 1;
10711static const int kFrameDetailsFunctionIndex = 2;
10712static const int kFrameDetailsArgumentCountIndex = 3;
10713static const int kFrameDetailsLocalCountIndex = 4;
10714static const int kFrameDetailsSourcePositionIndex = 5;
10715static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010716static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010717static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010718static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010719
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010720
10721static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10722 JavaScriptFrame* frame) {
10723 SaveContext* save = isolate->save_context();
10724 while (save != NULL && !save->IsBelowFrame(frame)) {
10725 save = save->prev();
10726 }
10727 ASSERT(save != NULL);
10728 return save;
10729}
10730
10731
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010732// Return an array with frame details
10733// args[0]: number: break id
10734// args[1]: number: frame index
10735//
10736// The array returned contains the following information:
10737// 0: Frame id
10738// 1: Receiver
10739// 2: Function
10740// 3: Argument count
10741// 4: Local count
10742// 5: Source position
10743// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010744// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010745// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010746// Arguments name, value
10747// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010748// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010749RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010750 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010751 ASSERT(args.length() == 2);
10752
10753 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010754 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010755 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10756 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010757 if (!maybe_check->ToObject(&check)) return maybe_check;
10758 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010759 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010760 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010761
10762 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010763 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010764 if (id == StackFrame::NO_ID) {
10765 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010766 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010767 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010768
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010769 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010770
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010772 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010773 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010774 if (index < count + it.frame()->GetInlineCount()) break;
10775 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010777 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010778
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010779 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010780 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010781 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010782 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010783 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010784
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010785 // Traverse the saved contexts chain to find the active context for the
10786 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010787 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010788
10789 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010790 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791
10792 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010793 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010794 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010795
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010796 // Check for constructor frame. Inlined frames cannot be construct calls.
10797 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010798 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010799 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010800
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010801 // Get scope info and read from it for local variable information.
10802 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010803 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010804 Handle<ScopeInfo> scope_info(shared->scope_info());
10805 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807 // Get the locals names and values into a temporary array.
10808 //
10809 // TODO(1240907): Hide compiler-introduced stack variables
10810 // (e.g. .result)? For users of the debugger, they will probably be
10811 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010812 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010813 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010814
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010815 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010816 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010817 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010818 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010819 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010820 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010821 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010822 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010823 // Get the context containing declarations.
10824 Handle<Context> context(
10825 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010826 for (; i < scope_info->LocalCount(); ++i) {
10827 Handle<String> name(scope_info->LocalName(i));
10828 VariableMode mode;
10829 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010830 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010831 locals->set(i * 2 + 1, context->get(
10832 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010833 }
10834 }
10835
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010836 // Check whether this frame is positioned at return. If not top
10837 // frame or if the frame is optimized it cannot be at a return.
10838 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010839 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010840 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010841 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010842
10843 // If positioned just before return find the value to be returned and add it
10844 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010845 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010846 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010847 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010848 Address internal_frame_sp = NULL;
10849 while (!it2.done()) {
10850 if (it2.frame()->is_internal()) {
10851 internal_frame_sp = it2.frame()->sp();
10852 } else {
10853 if (it2.frame()->is_java_script()) {
10854 if (it2.frame()->id() == it.frame()->id()) {
10855 // The internal frame just before the JavaScript frame contains the
10856 // value to return on top. A debug break at return will create an
10857 // internal frame to store the return value (eax/rax/r0) before
10858 // entering the debug break exit frame.
10859 if (internal_frame_sp != NULL) {
10860 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010861 Handle<Object>(Memory::Object_at(internal_frame_sp),
10862 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010863 break;
10864 }
10865 }
10866 }
10867
10868 // Indicate that the previous frame was not an internal frame.
10869 internal_frame_sp = NULL;
10870 }
10871 it2.Advance();
10872 }
10873 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874
10875 // Now advance to the arguments adapter frame (if any). It contains all
10876 // the provided parameters whereas the function frame always have the number
10877 // of arguments matching the functions parameters. The rest of the
10878 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010879 if (it.frame()->has_adapted_arguments()) {
10880 it.AdvanceToArgumentsFrame();
10881 frame_inspector.SetArgumentsFrame(it.frame());
10882 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010883
10884 // Find the number of arguments to fill. At least fill the number of
10885 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010886 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010887 if (argument_count < frame_inspector.GetParametersCount()) {
10888 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010889 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010890#ifdef DEBUG
10891 if (it.frame()->is_optimized()) {
10892 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10893 }
10894#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010895
10896 // Calculate the size of the result.
10897 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010898 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010899 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010900 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010901
10902 // Add the frame id.
10903 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10904
10905 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010906 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010907
10908 // Add the arguments count.
10909 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10910
10911 // Add the locals count
10912 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010913 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010914
10915 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010916 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10918 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010919 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010920 }
10921
10922 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010923 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010924
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010925 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010926 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010927
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010928 // Add flags to indicate information on whether this frame is
10929 // bit 0: invoked in the debugger context.
10930 // bit 1: optimized frame.
10931 // bit 2: inlined in optimized frame
10932 int flags = 0;
10933 if (*save->context() == *isolate->debug()->debug_context()) {
10934 flags |= 1 << 0;
10935 }
10936 if (it.frame()->is_optimized()) {
10937 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010938 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010939 }
10940 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010941
10942 // Fill the dynamic part.
10943 int details_index = kFrameDetailsFirstDynamicIndex;
10944
10945 // Add arguments name and value.
10946 for (int i = 0; i < argument_count; i++) {
10947 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010948 if (i < scope_info->ParameterCount()) {
10949 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010951 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010952 }
10953
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010954 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010955 if (i < it.frame()->ComputeParametersCount()) {
10956 // Get the value from the stack.
10957 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010958 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010959 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960 }
10961 }
10962
10963 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010964 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010965 details->set(details_index++, locals->get(i));
10966 }
10967
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010968 // Add the value being returned.
10969 if (at_return) {
10970 details->set(details_index++, *return_value);
10971 }
10972
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010973 // Add the receiver (same as in function frame).
10974 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10975 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010976 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010977 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10978 // If the receiver is not a JSObject and the function is not a
10979 // builtin or strict-mode we have hit an optimization where a
10980 // value object is not converted into a wrapped JS objects. To
10981 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010982 // by creating correct wrapper object based on the calling frame's
10983 // global context.
10984 it.Advance();
10985 Handle<Context> calling_frames_global_context(
10986 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010987 receiver =
10988 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010989 }
10990 details->set(kFrameDetailsReceiverIndex, *receiver);
10991
10992 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010993 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010994}
10995
10996
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010997// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010998static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010999 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011000 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011001 Handle<Context> context,
11002 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011003 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011004 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11005 VariableMode mode;
11006 InitializationFlag init_flag;
11007 int context_index = scope_info->ContextSlotIndex(
11008 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011009
whesse@chromium.org7b260152011-06-20 15:33:18 +000011010 RETURN_IF_EMPTY_HANDLE_VALUE(
11011 isolate,
11012 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011013 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011014 Handle<Object>(context->get(context_index), isolate),
11015 NONE,
11016 kNonStrictMode),
11017 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011018 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011019
11020 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011021}
11022
11023
11024// Create a plain JSObject which materializes the local scope for the specified
11025// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011026static Handle<JSObject> MaterializeLocalScope(
11027 Isolate* isolate,
11028 JavaScriptFrame* frame,
11029 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011030 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011031 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011032 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011033 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011034
11035 // Allocate and initialize a JSObject with all the arguments, stack locals
11036 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011037 Handle<JSObject> local_scope =
11038 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011039
11040 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011041 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011042 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011043 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011044 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011045 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011046 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011047 NONE,
11048 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011049 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011050 }
11051
11052 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011053 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011054 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011055 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011056 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011057 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011058 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011059 NONE,
11060 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011061 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011062 }
11063
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011064 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011065 // Third fill all context locals.
11066 Handle<Context> frame_context(Context::cast(frame->context()));
11067 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011068 if (!CopyContextLocalsToScopeObject(
11069 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011070 return Handle<JSObject>();
11071 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011072
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011073 // Finally copy any properties from the function context extension.
11074 // These will be variables introduced by eval.
11075 if (function_context->closure() == *function) {
11076 if (function_context->has_extension() &&
11077 !function_context->IsGlobalContext()) {
11078 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011079 bool threw = false;
11080 Handle<FixedArray> keys =
11081 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11082 if (threw) return Handle<JSObject>();
11083
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011084 for (int i = 0; i < keys->length(); i++) {
11085 // Names of variables introduced by eval are strings.
11086 ASSERT(keys->get(i)->IsString());
11087 Handle<String> key(String::cast(keys->get(i)));
11088 RETURN_IF_EMPTY_HANDLE_VALUE(
11089 isolate,
11090 SetProperty(local_scope,
11091 key,
11092 GetProperty(ext, key),
11093 NONE,
11094 kNonStrictMode),
11095 Handle<JSObject>());
11096 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011097 }
11098 }
11099 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011100
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011101 return local_scope;
11102}
11103
11104
11105// Create a plain JSObject which materializes the closure content for the
11106// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011107static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11108 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011109 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011110
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011111 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011112 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011113
11114 // Allocate and initialize a JSObject with all the content of theis function
11115 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011116 Handle<JSObject> closure_scope =
11117 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011118
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011119 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011120 if (!CopyContextLocalsToScopeObject(
11121 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011122 return Handle<JSObject>();
11123 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011124
11125 // Finally copy any properties from the function context extension. This will
11126 // be variables introduced by eval.
11127 if (context->has_extension()) {
11128 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011129 bool threw = false;
11130 Handle<FixedArray> keys =
11131 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11132 if (threw) return Handle<JSObject>();
11133
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011134 for (int i = 0; i < keys->length(); i++) {
11135 // Names of variables introduced by eval are strings.
11136 ASSERT(keys->get(i)->IsString());
11137 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011138 RETURN_IF_EMPTY_HANDLE_VALUE(
11139 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011140 SetProperty(closure_scope,
11141 key,
11142 GetProperty(ext, key),
11143 NONE,
11144 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011145 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011146 }
11147 }
11148
11149 return closure_scope;
11150}
11151
11152
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011153// Create a plain JSObject which materializes the scope for the specified
11154// catch context.
11155static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11156 Handle<Context> context) {
11157 ASSERT(context->IsCatchContext());
11158 Handle<String> name(String::cast(context->extension()));
11159 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11160 Handle<JSObject> catch_scope =
11161 isolate->factory()->NewJSObject(isolate->object_function());
11162 RETURN_IF_EMPTY_HANDLE_VALUE(
11163 isolate,
11164 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11165 Handle<JSObject>());
11166 return catch_scope;
11167}
11168
11169
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011170// Create a plain JSObject which materializes the block scope for the specified
11171// block context.
11172static Handle<JSObject> MaterializeBlockScope(
11173 Isolate* isolate,
11174 Handle<Context> context) {
11175 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011176 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011177
11178 // Allocate and initialize a JSObject with all the arguments, stack locals
11179 // heap locals and extension properties of the debugged function.
11180 Handle<JSObject> block_scope =
11181 isolate->factory()->NewJSObject(isolate->object_function());
11182
11183 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011184 if (!CopyContextLocalsToScopeObject(
11185 isolate, scope_info, context, block_scope)) {
11186 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011187 }
11188
11189 return block_scope;
11190}
11191
11192
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011193// Iterate over the actual scopes visible from a stack frame. The iteration
11194// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011195// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011196// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011197class ScopeIterator {
11198 public:
11199 enum ScopeType {
11200 ScopeTypeGlobal = 0,
11201 ScopeTypeLocal,
11202 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011203 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011204 ScopeTypeCatch,
11205 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011206 };
11207
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011208 ScopeIterator(Isolate* isolate,
11209 JavaScriptFrame* frame,
11210 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011211 : isolate_(isolate),
11212 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011213 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011214 function_(JSFunction::cast(frame->function())),
11215 context_(Context::cast(frame->context())),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011216 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011217
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011218 // Catch the case when the debugger stops in an internal function.
11219 Handle<SharedFunctionInfo> shared_info(function_->shared());
11220 if (shared_info->script() == isolate->heap()->undefined_value()) {
11221 while (context_->closure() == *function_) {
11222 context_ = Handle<Context>(context_->previous(), isolate_);
11223 }
11224 return;
11225 }
11226
11227 // Check whether we are in global code or function code. If there is a stack
11228 // slot for .result then this function has been created for evaluating
11229 // global code and it is not a real function.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011230 // Checking for the existence of .result seems fragile, but the scope info
11231 // saved with the code object does not otherwise have that information.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011232 int index = shared_info->scope_info()->
lrn@chromium.org34e60782011-09-15 07:25:40 +000011233 StackSlotIndex(isolate_->heap()->result_symbol());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011234
11235 // Reparse the code and analyze the scopes.
11236 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11237 Handle<Script> script(Script::cast(shared_info->script()));
11238 Scope* scope;
lrn@chromium.org34e60782011-09-15 07:25:40 +000011239 if (index >= 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011240 // Global code
11241 CompilationInfo info(script);
11242 info.MarkAsGlobal();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011243 CHECK(ParserApi::Parse(&info));
11244 CHECK(Scope::Analyze(&info));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011245 scope = info.function()->scope();
11246 } else {
11247 // Function code
11248 CompilationInfo info(shared_info);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011249 CHECK(ParserApi::Parse(&info));
11250 CHECK(Scope::Analyze(&info));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011251 scope = info.function()->scope();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011252 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011253
11254 // Retrieve the scope chain for the current position.
11255 int statement_position =
11256 shared_info->code()->SourceStatementPosition(frame_->pc());
11257 scope->GetNestedScopeChain(&nested_scope_chain_, statement_position);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011258 }
11259
11260 // More scopes?
11261 bool Done() { return context_.is_null(); }
11262
11263 // Move to the next scope.
11264 void Next() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011265 ScopeType scope_type = Type();
11266 if (scope_type == ScopeTypeGlobal) {
11267 // The global scope is always the last in the chain.
11268 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011269 context_ = Handle<Context>();
11270 return;
11271 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011272 if (nested_scope_chain_.is_empty()) {
11273 context_ = Handle<Context>(context_->previous(), isolate_);
11274 } else {
11275 if (nested_scope_chain_.last()->HasContext()) {
11276 context_ = Handle<Context>(context_->previous(), isolate_);
11277 }
11278 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011279 }
11280 }
11281
11282 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011283 ScopeType Type() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011284 if (!nested_scope_chain_.is_empty()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011285 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011286 switch (scope_info->Type()) {
11287 case FUNCTION_SCOPE:
11288 ASSERT(context_->IsFunctionContext() ||
11289 !scope_info->HasContext());
11290 return ScopeTypeLocal;
11291 case GLOBAL_SCOPE:
11292 ASSERT(context_->IsGlobalContext());
11293 return ScopeTypeGlobal;
11294 case WITH_SCOPE:
11295 ASSERT(context_->IsWithContext());
11296 return ScopeTypeWith;
11297 case CATCH_SCOPE:
11298 ASSERT(context_->IsCatchContext());
11299 return ScopeTypeCatch;
11300 case BLOCK_SCOPE:
11301 ASSERT(!scope_info->HasContext() ||
11302 context_->IsBlockContext());
11303 return ScopeTypeBlock;
11304 case EVAL_SCOPE:
11305 UNREACHABLE();
11306 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011307 }
11308 if (context_->IsGlobalContext()) {
11309 ASSERT(context_->global()->IsGlobalObject());
11310 return ScopeTypeGlobal;
11311 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011312 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011313 return ScopeTypeClosure;
11314 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011315 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011316 return ScopeTypeCatch;
11317 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011318 if (context_->IsBlockContext()) {
11319 return ScopeTypeBlock;
11320 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011321 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011322 return ScopeTypeWith;
11323 }
11324
11325 // Return the JavaScript object with the content of the current scope.
11326 Handle<JSObject> ScopeObject() {
11327 switch (Type()) {
11328 case ScopeIterator::ScopeTypeGlobal:
11329 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011330 case ScopeIterator::ScopeTypeLocal:
11331 // Materialize the content of the local scope into a JSObject.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011332 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011333 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011334 case ScopeIterator::ScopeTypeWith:
11335 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011336 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11337 case ScopeIterator::ScopeTypeCatch:
11338 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011339 case ScopeIterator::ScopeTypeClosure:
11340 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011341 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011342 case ScopeIterator::ScopeTypeBlock:
11343 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011344 }
11345 UNREACHABLE();
11346 return Handle<JSObject>();
11347 }
11348
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011349 Handle<ScopeInfo> CurrentScopeInfo() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011350 if (!nested_scope_chain_.is_empty()) {
11351 return nested_scope_chain_.last();
11352 } else if (context_->IsBlockContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011353 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011354 } else if (context_->IsFunctionContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011355 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011356 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011357 return Handle<ScopeInfo>::null();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011358 }
11359
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011360 // Return the context for this scope. For the local context there might not
11361 // be an actual context.
11362 Handle<Context> CurrentContext() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011363 if (Type() == ScopeTypeGlobal ||
11364 nested_scope_chain_.is_empty()) {
11365 return context_;
11366 } else if (nested_scope_chain_.last()->HasContext()) {
11367 return context_;
11368 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011369 return Handle<Context>();
11370 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011371 }
11372
11373#ifdef DEBUG
11374 // Debug print of the content of the current scope.
11375 void DebugPrint() {
11376 switch (Type()) {
11377 case ScopeIterator::ScopeTypeGlobal:
11378 PrintF("Global:\n");
11379 CurrentContext()->Print();
11380 break;
11381
11382 case ScopeIterator::ScopeTypeLocal: {
11383 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011384 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011385 if (!CurrentContext().is_null()) {
11386 CurrentContext()->Print();
11387 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011388 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011389 if (extension->IsJSContextExtensionObject()) {
11390 extension->Print();
11391 }
11392 }
11393 }
11394 break;
11395 }
11396
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011397 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011398 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011399 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011400 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011401
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011402 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011403 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011404 CurrentContext()->extension()->Print();
11405 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011406 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011408 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011409 PrintF("Closure:\n");
11410 CurrentContext()->Print();
11411 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011412 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011413 if (extension->IsJSContextExtensionObject()) {
11414 extension->Print();
11415 }
11416 }
11417 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011418
11419 default:
11420 UNREACHABLE();
11421 }
11422 PrintF("\n");
11423 }
11424#endif
11425
11426 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011427 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011428 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011429 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011430 Handle<JSFunction> function_;
11431 Handle<Context> context_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011432 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011433
11434 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11435};
11436
11437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011438RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011439 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011440 ASSERT(args.length() == 2);
11441
11442 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011443 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011444 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11445 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011446 if (!maybe_check->ToObject(&check)) return maybe_check;
11447 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011448 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11449
11450 // Get the frame where the debugging is performed.
11451 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011452 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011453 JavaScriptFrame* frame = it.frame();
11454
11455 // Count the visible scopes.
11456 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011457 for (ScopeIterator it(isolate, frame, 0);
11458 !it.Done();
11459 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011460 n++;
11461 }
11462
11463 return Smi::FromInt(n);
11464}
11465
11466
11467static const int kScopeDetailsTypeIndex = 0;
11468static const int kScopeDetailsObjectIndex = 1;
11469static const int kScopeDetailsSize = 2;
11470
11471// Return an array with scope details
11472// args[0]: number: break id
11473// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011474// args[2]: number: inlined frame index
11475// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011476//
11477// The array returned contains the following information:
11478// 0: Scope type
11479// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011480RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011481 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011482 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011483
11484 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011485 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011486 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11487 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011488 if (!maybe_check->ToObject(&check)) return maybe_check;
11489 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011490 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011491 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11492 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011493
11494 // Get the frame where the debugging is performed.
11495 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011496 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011497 JavaScriptFrame* frame = frame_it.frame();
11498
11499 // Find the requested scope.
11500 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011501 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011502 for (; !it.Done() && n < index; it.Next()) {
11503 n++;
11504 }
11505 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011506 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011507 }
11508
11509 // Calculate the size of the result.
11510 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011511 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011512
11513 // Fill in scope details.
11514 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011515 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011516 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011517 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011518
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011519 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011520}
11521
11522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011523RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011524 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011525 ASSERT(args.length() == 0);
11526
11527#ifdef DEBUG
11528 // Print the scopes for the top frame.
11529 StackFrameLocator locator;
11530 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011531 for (ScopeIterator it(isolate, frame, 0);
11532 !it.Done();
11533 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011534 it.DebugPrint();
11535 }
11536#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011537 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011538}
11539
11540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011541RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011542 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011543 ASSERT(args.length() == 1);
11544
11545 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011546 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011547 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11548 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011549 if (!maybe_result->ToObject(&result)) return maybe_result;
11550 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011551
11552 // Count all archived V8 threads.
11553 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 for (ThreadState* thread =
11555 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011556 thread != NULL;
11557 thread = thread->Next()) {
11558 n++;
11559 }
11560
11561 // Total number of threads is current thread and archived threads.
11562 return Smi::FromInt(n + 1);
11563}
11564
11565
11566static const int kThreadDetailsCurrentThreadIndex = 0;
11567static const int kThreadDetailsThreadIdIndex = 1;
11568static const int kThreadDetailsSize = 2;
11569
11570// Return an array with thread details
11571// args[0]: number: break id
11572// args[1]: number: thread index
11573//
11574// The array returned contains the following information:
11575// 0: Is current thread?
11576// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011577RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011579 ASSERT(args.length() == 2);
11580
11581 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011582 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011583 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11584 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011585 if (!maybe_check->ToObject(&check)) return maybe_check;
11586 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011587 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11588
11589 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011590 Handle<FixedArray> details =
11591 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011592
11593 // Thread index 0 is current thread.
11594 if (index == 0) {
11595 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011596 details->set(kThreadDetailsCurrentThreadIndex,
11597 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011598 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011599 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011600 } else {
11601 // Find the thread with the requested index.
11602 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011603 ThreadState* thread =
11604 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011605 while (index != n && thread != NULL) {
11606 thread = thread->Next();
11607 n++;
11608 }
11609 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011610 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011611 }
11612
11613 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614 details->set(kThreadDetailsCurrentThreadIndex,
11615 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011616 details->set(kThreadDetailsThreadIdIndex,
11617 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011618 }
11619
11620 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011622}
11623
11624
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011625// Sets the disable break state
11626// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011627RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011628 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011629 ASSERT(args.length() == 1);
11630 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011631 isolate->debug()->set_disable_break(disable_break);
11632 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011633}
11634
11635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011636RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011637 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011638 ASSERT(args.length() == 1);
11639
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011640 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11641 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011642 // Find the number of break points
11643 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011644 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011645 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647 Handle<FixedArray>::cast(break_locations));
11648}
11649
11650
11651// Set a break point in a function
11652// args[0]: function
11653// args[1]: number: break source position (within the function source)
11654// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011655RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011656 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011657 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011658 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11659 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011660 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11661 RUNTIME_ASSERT(source_position >= 0);
11662 Handle<Object> break_point_object_arg = args.at<Object>(2);
11663
11664 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011665 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11666 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011667
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011668 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011669}
11670
11671
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011672Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11673 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011674 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011675 // Iterate the heap looking for SharedFunctionInfo generated from the
11676 // script. The inner most SharedFunctionInfo containing the source position
11677 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011678 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011679 // which is found is not compiled it is compiled and the heap is iterated
11680 // again as the compilation might create inner functions from the newly
11681 // compiled function and the actual requested break point might be in one of
11682 // these functions.
11683 bool done = false;
11684 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011685 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011686 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011687 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011688 { // Extra scope for iterator and no-allocation.
11689 isolate->heap()->EnsureHeapIsIterable();
11690 AssertNoAllocation no_alloc_during_heap_iteration;
11691 HeapIterator iterator;
11692 for (HeapObject* obj = iterator.next();
11693 obj != NULL; obj = iterator.next()) {
11694 if (obj->IsSharedFunctionInfo()) {
11695 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11696 if (shared->script() == *script) {
11697 // If the SharedFunctionInfo found has the requested script data and
11698 // contains the source position it is a candidate.
11699 int start_position = shared->function_token_position();
11700 if (start_position == RelocInfo::kNoPosition) {
11701 start_position = shared->start_position();
11702 }
11703 if (start_position <= position &&
11704 position <= shared->end_position()) {
11705 // If there is no candidate or this function is within the current
11706 // candidate this is the new candidate.
11707 if (target.is_null()) {
11708 target_start_position = start_position;
11709 target = shared;
11710 } else {
11711 if (target_start_position == start_position &&
11712 shared->end_position() == target->end_position()) {
11713 // If a top-level function contain only one function
11714 // declartion the source for the top-level and the
11715 // function is the same. In that case prefer the non
11716 // top-level function.
11717 if (!shared->is_toplevel()) {
11718 target_start_position = start_position;
11719 target = shared;
11720 }
11721 } else if (target_start_position <= start_position &&
11722 shared->end_position() <= target->end_position()) {
11723 // This containment check includes equality as a function
11724 // inside a top-level function can share either start or end
11725 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011726 target_start_position = start_position;
11727 target = shared;
11728 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011729 }
11730 }
11731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011732 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011733 } // End for loop.
11734 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011735
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011736 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011737 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011738 }
11739
11740 // If the candidate found is compiled we are done. NOTE: when lazy
11741 // compilation of inner functions is introduced some additional checking
11742 // needs to be done here to compile inner functions.
11743 done = target->is_compiled();
11744 if (!done) {
11745 // If the candidate is not compiled compile it to reveal any inner
11746 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011747 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011748 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011749 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011750
11751 return *target;
11752}
11753
11754
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011755// Changes the state of a break point in a script and returns source position
11756// where break point was set. NOTE: Regarding performance see the NOTE for
11757// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011758// args[0]: script to set break point in
11759// args[1]: number: break source position (within the script source)
11760// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011761RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011762 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011763 ASSERT(args.length() == 3);
11764 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11765 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11766 RUNTIME_ASSERT(source_position >= 0);
11767 Handle<Object> break_point_object_arg = args.at<Object>(2);
11768
11769 // Get the script from the script wrapper.
11770 RUNTIME_ASSERT(wrapper->value()->IsScript());
11771 Handle<Script> script(Script::cast(wrapper->value()));
11772
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011773 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011774 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011775 if (!result->IsUndefined()) {
11776 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11777 // Find position within function. The script position might be before the
11778 // source position of the first function.
11779 int position;
11780 if (shared->start_position() > source_position) {
11781 position = 0;
11782 } else {
11783 position = source_position - shared->start_position();
11784 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011785 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011786 position += shared->start_position();
11787 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011788 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011789 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011790}
11791
11792
11793// Clear a break point
11794// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011795RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011796 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797 ASSERT(args.length() == 1);
11798 Handle<Object> break_point_object_arg = args.at<Object>(0);
11799
11800 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011801 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011802
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011803 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011804}
11805
11806
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011807// Change the state of break on exceptions.
11808// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11809// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011810RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011811 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011812 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011813 RUNTIME_ASSERT(args[0]->IsNumber());
11814 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011815
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011816 // If the number doesn't match an enum value, the ChangeBreakOnException
11817 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011818 ExceptionBreakType type =
11819 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011820 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011821 isolate->debug()->ChangeBreakOnException(type, enable);
11822 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011823}
11824
11825
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011826// Returns the state of break on exceptions
11827// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011828RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011829 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011830 ASSERT(args.length() == 1);
11831 RUNTIME_ASSERT(args[0]->IsNumber());
11832
11833 ExceptionBreakType type =
11834 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011835 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011836 return Smi::FromInt(result);
11837}
11838
11839
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011840// Prepare for stepping
11841// args[0]: break id for checking execution state
11842// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011843// args[2]: number of times to perform the step, for step out it is the number
11844// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011845RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011846 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011847 ASSERT(args.length() == 3);
11848 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011849 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011850 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11851 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011852 if (!maybe_check->ToObject(&check)) return maybe_check;
11853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011854 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011855 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011856 }
11857
11858 // Get the step action and check validity.
11859 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11860 if (step_action != StepIn &&
11861 step_action != StepNext &&
11862 step_action != StepOut &&
11863 step_action != StepInMin &&
11864 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011865 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011866 }
11867
11868 // Get the number of steps.
11869 int step_count = NumberToInt32(args[2]);
11870 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011871 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011872 }
11873
ager@chromium.orga1645e22009-09-09 19:27:10 +000011874 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011875 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011876
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011878 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11879 step_count);
11880 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881}
11882
11883
11884// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011885RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011886 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011887 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011888 isolate->debug()->ClearStepping();
11889 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011890}
11891
11892
11893// Creates a copy of the with context chain. The copy of the context chain is
11894// is linked to the function context supplied.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011895static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11896 Handle<JSFunction> function,
11897 Handle<Context> base,
11898 JavaScriptFrame* frame,
11899 int inlined_frame_index) {
11900 HandleScope scope(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011901 List<Handle<ScopeInfo> > scope_chain;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011902 List<Handle<Context> > context_chain;
11903
11904 ScopeIterator it(isolate, frame, inlined_frame_index);
11905 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11906 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11907 ASSERT(!it.Done());
11908 scope_chain.Add(it.CurrentScopeInfo());
11909 context_chain.Add(it.CurrentContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011910 }
11911
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011912 // At the end of the chain. Return the base context to link to.
11913 Handle<Context> context = base;
11914
11915 // Iteratively copy and or materialize the nested contexts.
11916 while (!scope_chain.is_empty()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011917 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011918 Handle<Context> current = context_chain.RemoveLast();
11919 ASSERT(!(scope_info->HasContext() & current.is_null()));
11920
11921 if (scope_info->Type() == CATCH_SCOPE) {
11922 Handle<String> name(String::cast(current->extension()));
11923 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11924 context =
11925 isolate->factory()->NewCatchContext(function,
11926 context,
11927 name,
11928 thrown_object);
11929 } else if (scope_info->Type() == BLOCK_SCOPE) {
11930 // Materialize the contents of the block scope into a JSObject.
11931 Handle<JSObject> block_scope_object =
11932 MaterializeBlockScope(isolate, current);
11933 if (block_scope_object.is_null()) {
11934 return Handle<Context>::null();
11935 }
11936 // Allocate a new function context for the debug evaluation and set the
11937 // extension object.
11938 Handle<Context> new_context =
11939 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11940 function);
11941 new_context->set_extension(*block_scope_object);
11942 new_context->set_previous(*context);
11943 context = new_context;
11944 } else {
11945 ASSERT(scope_info->Type() == WITH_SCOPE);
11946 ASSERT(current->IsWithContext());
11947 Handle<JSObject> extension(JSObject::cast(current->extension()));
11948 context =
11949 isolate->factory()->NewWithContext(function, context, extension);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011950 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011951 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011952
11953 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011954}
11955
11956
11957// Helper function to find or create the arguments object for
11958// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011959static Handle<Object> GetArgumentsObject(Isolate* isolate,
11960 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011961 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011962 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011963 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011964 Handle<Context> function_context) {
11965 // Try to find the value of 'arguments' to pass as parameter. If it is not
11966 // found (that is the debugged function does not reference 'arguments' and
11967 // does not support eval) then create an 'arguments' object.
11968 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011969 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011970 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011971 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011972 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011973 }
11974 }
11975
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011976 if (scope_info->HasHeapAllocatedLocals()) {
11977 VariableMode mode;
11978 InitializationFlag init_flag;
11979 index = scope_info->ContextSlotIndex(
11980 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011981 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011982 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011983 }
11984 }
11985
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011986 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11987
11988 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011989 Handle<JSObject> arguments =
11990 isolate->factory()->NewArgumentsObject(function, length);
11991 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011992
11993 AssertNoAllocation no_gc;
11994 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011995 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011996 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011997 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011998 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011999 return arguments;
12000}
12001
12002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012003static const char kSourceStr[] =
12004 "(function(arguments,__source__){return eval(__source__);})";
12005
12006
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012007// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012008// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012009// extension part has all the parameters and locals of the function on the
12010// stack frame. A function which calls eval with the code to evaluate is then
12011// compiled in this context and called in this context. As this context
12012// replaces the context of the function on the stack frame a new (empty)
12013// function is created as well to be used as the closure for the context.
12014// This function and the context acts as replacements for the function on the
12015// stack frame presenting the same view of the values of parameters and
12016// local variables as if the piece of JavaScript was evaluated at the point
12017// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012018RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012019 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012020
12021 // Check the execution state and decode arguments frame and source to be
12022 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012023 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012024 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012025 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12026 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012027 if (!maybe_check_result->ToObject(&check_result)) {
12028 return maybe_check_result;
12029 }
12030 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012031 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012032 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12033 CONVERT_ARG_CHECKED(String, source, 3);
12034 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12035 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012036
12037 // Handle the processing of break.
12038 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012039
12040 // Get the frame where the debugging is performed.
12041 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012042 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012043 JavaScriptFrame* frame = it.frame();
12044 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012045 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012046
12047 // Traverse the saved contexts chain to find the active context for the
12048 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012049 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012051 SaveContext savex(isolate);
12052 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012053
12054 // Create the (empty) function replacing the function on the stack frame for
12055 // the purpose of evaluating in the context created below. It is important
12056 // that this function does not describe any parameters and local variables
12057 // in the context. If it does then this will cause problems with the lookup
12058 // in Context::Lookup, where context slots for parameters and local variables
12059 // are looked at before the extension object.
12060 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012061 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12062 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012063 go_between->set_context(function->context());
12064#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012065 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12066 ASSERT(go_between_scope_info->ParameterCount() == 0);
12067 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012068#endif
12069
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012070 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012071 Handle<JSObject> local_scope = MaterializeLocalScope(
12072 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012073 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012074
12075 // Allocate a new context for the debug evaluation and set the extension
12076 // object build.
12077 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012078 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12079 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012080 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012081 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012082 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012083 Handle<Context> function_context;
12084 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012085 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012086 function_context = Handle<Context>(frame_context->declaration_context());
12087 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012088 context = CopyNestedScopeContextChain(isolate,
12089 go_between,
12090 context,
12091 frame,
12092 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012093
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012094 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012095 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012096 context =
12097 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012098 }
12099
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012100 // Wrap the evaluation statement in a new function compiled in the newly
12101 // created context. The function has one parameter which has to be called
12102 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012103 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012104 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012106 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012107 isolate->factory()->NewStringFromAscii(
12108 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012109
12110 // Currently, the eval code will be executed in non-strict mode,
12111 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012112 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012113 Compiler::CompileEval(function_source,
12114 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012115 context->IsGlobalContext(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012116 kNonStrictMode,
12117 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012118 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012119 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012120 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121
12122 // Invoke the result of the compilation to get the evaluation function.
12123 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012124 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012125 Handle<Object> evaluation_function =
12126 Execution::Call(compiled_function, receiver, 0, NULL,
12127 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012128 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012129
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012130 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012131 frame,
12132 inlined_frame_index,
12133 function,
12134 scope_info,
12135 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012136
12137 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012138 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012139 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012140 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12141 receiver,
12142 ARRAY_SIZE(argv),
12143 argv,
12144 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012145 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012146
12147 // Skip the global proxy as it has no properties and always delegates to the
12148 // real global object.
12149 if (result->IsJSGlobalProxy()) {
12150 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12151 }
12152
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012153 return *result;
12154}
12155
12156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012157RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012158 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012159
12160 // Check the execution state and decode arguments frame and source to be
12161 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012162 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012163 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012164 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12165 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012166 if (!maybe_check_result->ToObject(&check_result)) {
12167 return maybe_check_result;
12168 }
12169 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012170 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012171 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012172 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012173
12174 // Handle the processing of break.
12175 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012176
12177 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012178 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012179 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012180 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012181 top = top->prev();
12182 }
12183 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012184 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012185 }
12186
12187 // Get the global context now set to the top context from before the
12188 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012189 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012190
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012191 bool is_global = true;
12192
12193 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012194 // Create a new with context with the additional context information between
12195 // the context of the debugged function and the eval code to be executed.
12196 context = isolate->factory()->NewWithContext(
12197 Handle<JSFunction>(context->closure()),
12198 context,
12199 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012200 is_global = false;
12201 }
12202
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012203 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012204 // Currently, the eval code will be executed in non-strict mode,
12205 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012206 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012207 Compiler::CompileEval(source,
12208 context,
12209 is_global,
12210 kNonStrictMode,
12211 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012212 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012213 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012214 Handle<JSFunction>(
12215 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12216 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012217
12218 // Invoke the result of the compilation to get the evaluation function.
12219 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012220 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012221 Handle<Object> result =
12222 Execution::Call(compiled_function, receiver, 0, NULL,
12223 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012224 // Clear the oneshot breakpoints so that the debugger does not step further.
12225 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012226 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012227 return *result;
12228}
12229
12230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012231RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012232 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012233 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012234
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012235 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012236 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012237
12238 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012239 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012240 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12241 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12242 // because using
12243 // instances->set(i, *GetScriptWrapper(script))
12244 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12245 // already have deferenced the instances handle.
12246 Handle<JSValue> wrapper = GetScriptWrapper(script);
12247 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012248 }
12249
12250 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012251 Handle<JSObject> result =
12252 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012253 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012254 return *result;
12255}
12256
12257
12258// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012259static int DebugReferencedBy(HeapIterator* iterator,
12260 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012261 Object* instance_filter, int max_references,
12262 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012263 JSFunction* arguments_function) {
12264 NoHandleAllocation ha;
12265 AssertNoAllocation no_alloc;
12266
12267 // Iterate the heap.
12268 int count = 0;
12269 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012270 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012271 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012272 (max_references == 0 || count < max_references)) {
12273 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012274 if (heap_obj->IsJSObject()) {
12275 // Skip context extension objects and argument arrays as these are
12276 // checked in the context of functions using them.
12277 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012278 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012279 obj->map()->constructor() == arguments_function) {
12280 continue;
12281 }
12282
12283 // Check if the JS object has a reference to the object looked for.
12284 if (obj->ReferencesObject(target)) {
12285 // Check instance filter if supplied. This is normally used to avoid
12286 // references from mirror objects (see Runtime_IsInPrototypeChain).
12287 if (!instance_filter->IsUndefined()) {
12288 Object* V = obj;
12289 while (true) {
12290 Object* prototype = V->GetPrototype();
12291 if (prototype->IsNull()) {
12292 break;
12293 }
12294 if (instance_filter == prototype) {
12295 obj = NULL; // Don't add this object.
12296 break;
12297 }
12298 V = prototype;
12299 }
12300 }
12301
12302 if (obj != NULL) {
12303 // Valid reference found add to instance array if supplied an update
12304 // count.
12305 if (instances != NULL && count < instances_size) {
12306 instances->set(count, obj);
12307 }
12308 last = obj;
12309 count++;
12310 }
12311 }
12312 }
12313 }
12314
12315 // Check for circular reference only. This can happen when the object is only
12316 // referenced from mirrors and has a circular reference in which case the
12317 // object is not really alive and would have been garbage collected if not
12318 // referenced from the mirror.
12319 if (count == 1 && last == target) {
12320 count = 0;
12321 }
12322
12323 // Return the number of referencing objects found.
12324 return count;
12325}
12326
12327
12328// Scan the heap for objects with direct references to an object
12329// args[0]: the object to find references to
12330// args[1]: constructor function for instances to exclude (Mirror)
12331// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012332RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012333 ASSERT(args.length() == 3);
12334
12335 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012336 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12337 // The heap iterator reserves the right to do a GC to make the heap iterable.
12338 // Due to the GC above we know it won't need to do that, but it seems cleaner
12339 // to get the heap iterator constructed before we start having unprotected
12340 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012341
12342 // Check parameters.
12343 CONVERT_CHECKED(JSObject, target, args[0]);
12344 Object* instance_filter = args[1];
12345 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12346 instance_filter->IsJSObject());
12347 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12348 RUNTIME_ASSERT(max_references >= 0);
12349
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012350
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012351 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012352 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012353 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012354 JSFunction* arguments_function =
12355 JSFunction::cast(arguments_boilerplate->map()->constructor());
12356
12357 // Get the number of referencing objects.
12358 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012359 HeapIterator heap_iterator;
12360 count = DebugReferencedBy(&heap_iterator,
12361 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012362 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012363
12364 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012365 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012366 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012367 if (!maybe_object->ToObject(&object)) return maybe_object;
12368 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012369 FixedArray* instances = FixedArray::cast(object);
12370
12371 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012372 // AllocateFixedArray above does not make the heap non-iterable.
12373 ASSERT(HEAP->IsHeapIterable());
12374 HeapIterator heap_iterator2;
12375 count = DebugReferencedBy(&heap_iterator2,
12376 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012377 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012378
12379 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012380 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012381 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012382 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012383 if (!maybe_result->ToObject(&result)) return maybe_result;
12384 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012385}
12386
12387
12388// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012389static int DebugConstructedBy(HeapIterator* iterator,
12390 JSFunction* constructor,
12391 int max_references,
12392 FixedArray* instances,
12393 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012394 AssertNoAllocation no_alloc;
12395
12396 // Iterate the heap.
12397 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012398 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012399 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012400 (max_references == 0 || count < max_references)) {
12401 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012402 if (heap_obj->IsJSObject()) {
12403 JSObject* obj = JSObject::cast(heap_obj);
12404 if (obj->map()->constructor() == constructor) {
12405 // Valid reference found add to instance array if supplied an update
12406 // count.
12407 if (instances != NULL && count < instances_size) {
12408 instances->set(count, obj);
12409 }
12410 count++;
12411 }
12412 }
12413 }
12414
12415 // Return the number of referencing objects found.
12416 return count;
12417}
12418
12419
12420// Scan the heap for objects constructed by a specific function.
12421// args[0]: the constructor to find instances of
12422// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012423RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012424 ASSERT(args.length() == 2);
12425
12426 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012427 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012428
12429 // Check parameters.
12430 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12431 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12432 RUNTIME_ASSERT(max_references >= 0);
12433
12434 // Get the number of referencing objects.
12435 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012436 HeapIterator heap_iterator;
12437 count = DebugConstructedBy(&heap_iterator,
12438 constructor,
12439 max_references,
12440 NULL,
12441 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012442
12443 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012444 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012445 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012446 if (!maybe_object->ToObject(&object)) return maybe_object;
12447 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012448 FixedArray* instances = FixedArray::cast(object);
12449
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012450 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012451 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012452 HeapIterator heap_iterator2;
12453 count = DebugConstructedBy(&heap_iterator2,
12454 constructor,
12455 max_references,
12456 instances,
12457 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012458
12459 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012460 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012461 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12462 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012463 if (!maybe_result->ToObject(&result)) return maybe_result;
12464 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012465 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012466}
12467
12468
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012469// Find the effective prototype object as returned by __proto__.
12470// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012471RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012472 ASSERT(args.length() == 1);
12473
12474 CONVERT_CHECKED(JSObject, obj, args[0]);
12475
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012476 // Use the __proto__ accessor.
12477 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012478}
12479
12480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012481RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012482 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012483 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012484 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012485}
12486
12487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012488RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012489#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012490 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012491 ASSERT(args.length() == 1);
12492 // Get the function and make sure it is compiled.
12493 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012494 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012495 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012496 return Failure::Exception();
12497 }
12498 func->code()->PrintLn();
12499#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012500 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012501}
ager@chromium.org9085a012009-05-11 19:22:57 +000012502
12503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012504RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012505#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012506 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012507 ASSERT(args.length() == 1);
12508 // Get the function and make sure it is compiled.
12509 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012510 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012511 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012512 return Failure::Exception();
12513 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012514 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012515#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012516 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012517}
12518
12519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012520RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012521 NoHandleAllocation ha;
12522 ASSERT(args.length() == 1);
12523
12524 CONVERT_CHECKED(JSFunction, f, args[0]);
12525 return f->shared()->inferred_name();
12526}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012527
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012528
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012529static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12530 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012531 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012532 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012533 int counter = 0;
12534 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012535 for (HeapObject* obj = iterator->next();
12536 obj != NULL;
12537 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012538 ASSERT(obj != NULL);
12539 if (!obj->IsSharedFunctionInfo()) {
12540 continue;
12541 }
12542 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12543 if (shared->script() != script) {
12544 continue;
12545 }
12546 if (counter < buffer_size) {
12547 buffer->set(counter, shared);
12548 }
12549 counter++;
12550 }
12551 return counter;
12552}
12553
12554// For a script finds all SharedFunctionInfo's in the heap that points
12555// to this script. Returns JSArray of SharedFunctionInfo wrapped
12556// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012557RUNTIME_FUNCTION(MaybeObject*,
12558 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012559 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012560 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012561 CONVERT_CHECKED(JSValue, script_value, args[0]);
12562
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012563
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012564 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12565
12566 const int kBufferSize = 32;
12567
12568 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012569 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012570 int number;
12571 {
12572 isolate->heap()->EnsureHeapIsIterable();
12573 AssertNoAllocation no_allocations;
12574 HeapIterator heap_iterator;
12575 Script* scr = *script;
12576 FixedArray* arr = *array;
12577 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12578 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012579 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012580 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012581 isolate->heap()->EnsureHeapIsIterable();
12582 AssertNoAllocation no_allocations;
12583 HeapIterator heap_iterator;
12584 Script* scr = *script;
12585 FixedArray* arr = *array;
12586 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012587 }
12588
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012589 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012590 result->set_length(Smi::FromInt(number));
12591
12592 LiveEdit::WrapSharedFunctionInfos(result);
12593
12594 return *result;
12595}
12596
12597// For a script calculates compilation information about all its functions.
12598// The script source is explicitly specified by the second argument.
12599// The source of the actual script is not used, however it is important that
12600// all generated code keeps references to this particular instance of script.
12601// Returns a JSArray of compilation infos. The array is ordered so that
12602// each function with all its descendant is always stored in a continues range
12603// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012604RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012605 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012606 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012607 CONVERT_CHECKED(JSValue, script, args[0]);
12608 CONVERT_ARG_CHECKED(String, source, 1);
12609 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12610
12611 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12612
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012613 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012614 return Failure::Exception();
12615 }
12616
12617 return result;
12618}
12619
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012620// Changes the source of the script to a new_source.
12621// If old_script_name is provided (i.e. is a String), also creates a copy of
12622// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012623RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012624 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012625 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012626 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12627 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012628 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012629
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012630 CONVERT_CHECKED(Script, original_script_pointer,
12631 original_script_value->value());
12632 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012633
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012634 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12635 new_source,
12636 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012637
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012638 if (old_script->IsScript()) {
12639 Handle<Script> script_handle(Script::cast(old_script));
12640 return *(GetScriptWrapper(script_handle));
12641 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012642 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012643 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012644}
12645
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012647RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012648 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012649 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012650 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12651 return LiveEdit::FunctionSourceUpdated(shared_info);
12652}
12653
12654
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012655// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012656RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012657 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012658 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012659 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12660 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12661
ager@chromium.orgac091b72010-05-05 07:34:42 +000012662 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012663}
12664
12665// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012666RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012667 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012668 HandleScope scope(isolate);
12669 Handle<Object> function_object(args[0], isolate);
12670 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012671
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012672 if (function_object->IsJSValue()) {
12673 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12674 if (script_object->IsJSValue()) {
12675 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012676 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012677 }
12678
12679 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12680 } else {
12681 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12682 // and we check it in this function.
12683 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012684
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012685 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012686}
12687
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012688
12689// In a code of a parent function replaces original function as embedded object
12690// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012691RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012692 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012693 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012694
12695 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12696 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12697 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12698
12699 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12700 subst_wrapper);
12701
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012702 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012703}
12704
12705
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012706// Updates positions of a shared function info (first parameter) according
12707// to script source change. Text change is described in second parameter as
12708// array of groups of 3 numbers:
12709// (change_begin, change_end, change_end_new_position).
12710// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012711RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012712 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012713 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012714 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12715 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12716
ager@chromium.orgac091b72010-05-05 07:34:42 +000012717 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012718}
12719
12720
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012721// For array of SharedFunctionInfo's (each wrapped in JSValue)
12722// checks that none of them have activations on stacks (of any thread).
12723// Returns array of the same length with corresponding results of
12724// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012725RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012726 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012727 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012728 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012729 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012730
ager@chromium.org357bf652010-04-12 11:30:10 +000012731 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012732}
12733
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012734// Compares 2 strings line-by-line, then token-wise and returns diff in form
12735// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12736// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012737RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012738 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012739 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012740 CONVERT_ARG_CHECKED(String, s1, 0);
12741 CONVERT_ARG_CHECKED(String, s2, 1);
12742
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012743 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012744}
12745
12746
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012747// A testing entry. Returns statement position which is the closest to
12748// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012749RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012750 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012751 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012752 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12753 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12754
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012755 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012756
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012757 if (code->kind() != Code::FUNCTION &&
12758 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012759 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012760 }
12761
12762 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012763 int closest_pc = 0;
12764 int distance = kMaxInt;
12765 while (!it.done()) {
12766 int statement_position = static_cast<int>(it.rinfo()->data());
12767 // Check if this break point is closer that what was previously found.
12768 if (source_position <= statement_position &&
12769 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012770 closest_pc =
12771 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012772 distance = statement_position - source_position;
12773 // Check whether we can't get any closer.
12774 if (distance == 0) break;
12775 }
12776 it.next();
12777 }
12778
12779 return Smi::FromInt(closest_pc);
12780}
12781
12782
ager@chromium.org357bf652010-04-12 11:30:10 +000012783// Calls specified function with or without entering the debugger.
12784// This is used in unit tests to run code as if debugger is entered or simply
12785// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012786RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012787 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012788 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012789 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12790 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12791
12792 Handle<Object> result;
12793 bool pending_exception;
12794 {
12795 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012796 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012797 &pending_exception);
12798 } else {
12799 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012800 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012801 &pending_exception);
12802 }
12803 }
12804 if (!pending_exception) {
12805 return *result;
12806 } else {
12807 return Failure::Exception();
12808 }
12809}
12810
12811
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012812// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012813RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012814 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012815 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012816 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12817 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012818 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012819}
12820
12821
12822// Performs a GC.
12823// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012824RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012825 isolate->heap()->CollectAllGarbage(true);
12826 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012827}
12828
12829
12830// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012831RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012832 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012833 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012834 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012835 }
12836 return Smi::FromInt(usage);
12837}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012838
12839
12840// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012841RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012842#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012843 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012844#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012845 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012846#endif
12847}
12848
12849
12850// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012851RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012852#ifdef LIVE_OBJECT_LIST
12853 return LiveObjectList::Capture();
12854#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012855 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012856#endif
12857}
12858
12859
12860// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012861RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012862#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012863 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012864 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012865 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012866#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012867 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012868#endif
12869}
12870
12871
12872// Generates the response to a debugger request for a dump of the objects
12873// contained in the difference between the captured live object lists
12874// specified by id1 and id2.
12875// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12876// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012877RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012878#ifdef LIVE_OBJECT_LIST
12879 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012880 CONVERT_SMI_ARG_CHECKED(id1, 0);
12881 CONVERT_SMI_ARG_CHECKED(id2, 1);
12882 CONVERT_SMI_ARG_CHECKED(start, 2);
12883 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012884 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12885 EnterDebugger enter_debugger;
12886 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12887#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012888 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012889#endif
12890}
12891
12892
12893// Gets the specified object as requested by the debugger.
12894// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012895RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012896#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012897 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012898 Object* result = LiveObjectList::GetObj(obj_id);
12899 return result;
12900#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012901 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012902#endif
12903}
12904
12905
12906// Gets the obj id for the specified address if valid.
12907// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012908RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012909#ifdef LIVE_OBJECT_LIST
12910 HandleScope scope;
12911 CONVERT_ARG_CHECKED(String, address, 0);
12912 Object* result = LiveObjectList::GetObjId(address);
12913 return result;
12914#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012915 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012916#endif
12917}
12918
12919
12920// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012921RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012922#ifdef LIVE_OBJECT_LIST
12923 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012924 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012925 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12926 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12927 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12928 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12929 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12930
12931 Handle<JSObject> instance_filter;
12932 if (args[1]->IsJSObject()) {
12933 instance_filter = args.at<JSObject>(1);
12934 }
12935 bool verbose = false;
12936 if (args[2]->IsBoolean()) {
12937 verbose = args[2]->IsTrue();
12938 }
12939 int start = 0;
12940 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012941 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012942 }
12943 int limit = Smi::kMaxValue;
12944 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012945 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012946 }
12947
12948 return LiveObjectList::GetObjRetainers(obj_id,
12949 instance_filter,
12950 verbose,
12951 start,
12952 limit,
12953 filter_obj);
12954#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012955 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012956#endif
12957}
12958
12959
12960// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012961RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012962#ifdef LIVE_OBJECT_LIST
12963 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012964 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12965 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012966 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12967
12968 Handle<JSObject> instance_filter;
12969 if (args[2]->IsJSObject()) {
12970 instance_filter = args.at<JSObject>(2);
12971 }
12972
12973 Object* result =
12974 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12975 return result;
12976#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012977 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012978#endif
12979}
12980
12981
12982// Generates the response to a debugger request for a list of all
12983// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012984RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012985#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012986 CONVERT_SMI_ARG_CHECKED(start, 0);
12987 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012988 return LiveObjectList::Info(start, count);
12989#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012990 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012991#endif
12992}
12993
12994
12995// Gets a dump of the specified object as requested by the debugger.
12996// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012997RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012998#ifdef LIVE_OBJECT_LIST
12999 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013000 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013001 Object* result = LiveObjectList::PrintObj(obj_id);
13002 return result;
13003#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013004 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013005#endif
13006}
13007
13008
13009// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013010RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013011#ifdef LIVE_OBJECT_LIST
13012 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013013 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013014#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013015 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013016#endif
13017}
13018
13019
13020// Generates the response to a debugger request for a summary of the types
13021// of objects in the difference between the captured live object lists
13022// specified by id1 and id2.
13023// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13024// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013025RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013026#ifdef LIVE_OBJECT_LIST
13027 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013028 CONVERT_SMI_ARG_CHECKED(id1, 0);
13029 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013030 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13031
13032 EnterDebugger enter_debugger;
13033 return LiveObjectList::Summarize(id1, id2, filter_obj);
13034#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013035 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013036#endif
13037}
13038
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013039#endif // ENABLE_DEBUGGER_SUPPORT
13040
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013042RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013043 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013044 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013045 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013046}
13047
13048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013049RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013050 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013051 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013052 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013053}
13054
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013055
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013056// Finds the script object from the script data. NOTE: This operation uses
13057// heap traversal to find the function generated for the source position
13058// for the requested break point. For lazily compiled functions several heap
13059// traversals might be required rendering this operation as a rather slow
13060// operation. However for setting break points which is normally done through
13061// some kind of user interaction the performance is not crucial.
13062static Handle<Object> Runtime_GetScriptFromScriptName(
13063 Handle<String> script_name) {
13064 // Scan the heap for Script objects to find the script with the requested
13065 // script data.
13066 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013067 script_name->GetHeap()->EnsureHeapIsIterable();
13068 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013069 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013070 HeapObject* obj = NULL;
13071 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013072 // If a script is found check if it has the script data requested.
13073 if (obj->IsScript()) {
13074 if (Script::cast(obj)->name()->IsString()) {
13075 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13076 script = Handle<Script>(Script::cast(obj));
13077 }
13078 }
13079 }
13080 }
13081
13082 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013083 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013084
13085 // Return the script found.
13086 return GetScriptWrapper(script);
13087}
13088
13089
13090// Get the script object from script data. NOTE: Regarding performance
13091// see the NOTE for GetScriptFromScriptData.
13092// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013093RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013094 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013095
13096 ASSERT(args.length() == 1);
13097
13098 CONVERT_CHECKED(String, script_name, args[0]);
13099
13100 // Find the requested script.
13101 Handle<Object> result =
13102 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13103 return *result;
13104}
13105
13106
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013107// Determines whether the given stack frame should be displayed in
13108// a stack trace. The caller is the error constructor that asked
13109// for the stack trace to be collected. The first time a construct
13110// call to this function is encountered it is skipped. The seen_caller
13111// in/out parameter is used to remember if the caller has been seen
13112// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013113static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13114 Object* caller,
13115 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013116 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013117 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013118 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013119 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013120 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13121 Object* raw_fun = frame->function();
13122 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013123 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013124 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013125 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013126 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013127 *seen_caller = true;
13128 return false;
13129 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013130 // Skip all frames until we've seen the caller.
13131 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013132 // Also, skip non-visible built-in functions and any call with the builtins
13133 // object as receiver, so as to not reveal either the builtins object or
13134 // an internal function.
13135 // The --builtins-in-stack-traces command line flag allows including
13136 // internal call sites in the stack trace for debugging purposes.
13137 if (!FLAG_builtins_in_stack_traces) {
13138 JSFunction* fun = JSFunction::cast(raw_fun);
13139 if (frame->receiver()->IsJSBuiltinsObject() ||
13140 (fun->IsBuiltin() && !fun->shared()->native())) {
13141 return false;
13142 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013143 }
13144 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013145}
13146
13147
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013148// Collect the raw data for a stack trace. Returns an array of 4
13149// element segments each containing a receiver, function, code and
13150// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013151RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013152 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013153 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013154 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013156 HandleScope scope(isolate);
13157 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013158
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013159 limit = Max(limit, 0); // Ensure that limit is not negative.
13160 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013161 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013162 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013163
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013164 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013165 // If the caller parameter is a function we skip frames until we're
13166 // under it before starting to collect.
13167 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013168 int cursor = 0;
13169 int frames_seen = 0;
13170 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013171 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013172 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013173 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013174 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013175 // Set initial size to the maximum inlining level + 1 for the outermost
13176 // function.
13177 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013178 frame->Summarize(&frames);
13179 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013180 if (cursor + 4 > elements->length()) {
13181 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13182 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013183 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013184 for (int i = 0; i < cursor; i++) {
13185 new_elements->set(i, elements->get(i));
13186 }
13187 elements = new_elements;
13188 }
13189 ASSERT(cursor + 4 <= elements->length());
13190
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013191 Handle<Object> recv = frames[i].receiver();
13192 Handle<JSFunction> fun = frames[i].function();
13193 Handle<Code> code = frames[i].code();
13194 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013195 elements->set(cursor++, *recv);
13196 elements->set(cursor++, *fun);
13197 elements->set(cursor++, *code);
13198 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013199 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013200 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013201 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013203 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013204 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013205 return *result;
13206}
13207
13208
ager@chromium.org3811b432009-10-28 14:53:37 +000013209// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013210RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013211 ASSERT_EQ(args.length(), 0);
13212
13213 NoHandleAllocation ha;
13214
13215 const char* version_string = v8::V8::GetVersion();
13216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013217 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13218 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013219}
13220
13221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013222RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013223 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013224 OS::PrintError("abort: %s\n",
13225 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013226 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013227 OS::Abort();
13228 UNREACHABLE();
13229 return NULL;
13230}
13231
13232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013233RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013234 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013235 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013236 Object* key = args[1];
13237
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013238 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013239 Object* o = cache->get(finger_index);
13240 if (o == key) {
13241 // The fastest case: hit the same place again.
13242 return cache->get(finger_index + 1);
13243 }
13244
13245 for (int i = finger_index - 2;
13246 i >= JSFunctionResultCache::kEntriesIndex;
13247 i -= 2) {
13248 o = cache->get(i);
13249 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013250 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013251 return cache->get(i + 1);
13252 }
13253 }
13254
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013255 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013256 ASSERT(size <= cache->length());
13257
13258 for (int i = size - 2; i > finger_index; i -= 2) {
13259 o = cache->get(i);
13260 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013261 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013262 return cache->get(i + 1);
13263 }
13264 }
13265
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013266 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013267 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013268
13269 Handle<JSFunctionResultCache> cache_handle(cache);
13270 Handle<Object> key_handle(key);
13271 Handle<Object> value;
13272 {
13273 Handle<JSFunction> factory(JSFunction::cast(
13274 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13275 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013276 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013277 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013278 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013279 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013280 value = Execution::Call(factory,
13281 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013282 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013283 argv,
13284 &pending_exception);
13285 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013286 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013287
13288#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013289 if (FLAG_verify_heap) {
13290 cache_handle->JSFunctionResultCacheVerify();
13291 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013292#endif
13293
13294 // Function invocation may have cleared the cache. Reread all the data.
13295 finger_index = cache_handle->finger_index();
13296 size = cache_handle->size();
13297
13298 // If we have spare room, put new data into it, otherwise evict post finger
13299 // entry which is likely to be the least recently used.
13300 int index = -1;
13301 if (size < cache_handle->length()) {
13302 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13303 index = size;
13304 } else {
13305 index = finger_index + JSFunctionResultCache::kEntrySize;
13306 if (index == cache_handle->length()) {
13307 index = JSFunctionResultCache::kEntriesIndex;
13308 }
13309 }
13310
13311 ASSERT(index % 2 == 0);
13312 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13313 ASSERT(index < cache_handle->length());
13314
13315 cache_handle->set(index, *key_handle);
13316 cache_handle->set(index + 1, *value);
13317 cache_handle->set_finger_index(index);
13318
13319#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013320 if (FLAG_verify_heap) {
13321 cache_handle->JSFunctionResultCacheVerify();
13322 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013323#endif
13324
13325 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013326}
13327
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013329RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013330 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013331 CONVERT_ARG_CHECKED(String, type, 0);
13332 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013333 return *isolate->factory()->NewJSMessageObject(
13334 type,
13335 arguments,
13336 0,
13337 0,
13338 isolate->factory()->undefined_value(),
13339 isolate->factory()->undefined_value(),
13340 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013341}
13342
13343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013344RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013345 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13346 return message->type();
13347}
13348
13349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013350RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013351 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13352 return message->arguments();
13353}
13354
13355
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013356RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013357 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13358 return Smi::FromInt(message->start_position());
13359}
13360
13361
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013362RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013363 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13364 return message->script();
13365}
13366
13367
kasper.lund44510672008-07-25 07:37:58 +000013368#ifdef DEBUG
13369// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13370// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013371RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013372 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013373 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013374#define COUNT_ENTRY(Name, argc, ressize) + 1
13375 int entry_count = 0
13376 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13377 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13378 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13379#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013380 Factory* factory = isolate->factory();
13381 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013382 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013383 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013384#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013385 { \
13386 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013387 Handle<String> name; \
13388 /* Inline runtime functions have an underscore in front of the name. */ \
13389 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013390 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013391 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13392 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013393 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013394 Vector<const char>(#Name, StrLength(#Name))); \
13395 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013396 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013397 pair_elements->set(0, *name); \
13398 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013399 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013400 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013401 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013402 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013403 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013404 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013405 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013406 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013407#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013408 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013409 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013410 return *result;
13411}
kasper.lund44510672008-07-25 07:37:58 +000013412#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013413
13414
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013415RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013416 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013417 CONVERT_CHECKED(String, format, args[0]);
13418 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013419 String::FlatContent format_content = format->GetFlatContent();
13420 RUNTIME_ASSERT(format_content.IsAscii());
13421 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013422 LOGGER->LogRuntime(chars, elms);
13423 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013424}
13425
13426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013427RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013428 UNREACHABLE(); // implemented as macro in the parser
13429 return NULL;
13430}
13431
13432
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013433#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13434 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13435 CONVERT_CHECKED(JSObject, obj, args[0]); \
13436 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13437 }
13438
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013439ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013440ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13441ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13442ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13443ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13444ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13445ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13446ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13447ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13448ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13449ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13450ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13451ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13452ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13453
13454#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13455
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013456
13457RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13458 ASSERT(args.length() == 2);
13459 CONVERT_CHECKED(JSObject, obj1, args[0]);
13460 CONVERT_CHECKED(JSObject, obj2, args[1]);
13461 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13462}
13463
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013464// ----------------------------------------------------------------------------
13465// Implementation of Runtime
13466
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013467#define F(name, number_of_args, result_size) \
13468 { Runtime::k##name, Runtime::RUNTIME, #name, \
13469 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013470
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013471
13472#define I(name, number_of_args, result_size) \
13473 { Runtime::kInline##name, Runtime::INLINE, \
13474 "_" #name, NULL, number_of_args, result_size },
13475
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013476static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013477 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013478 INLINE_FUNCTION_LIST(I)
13479 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013480};
13481
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013482
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013483MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13484 Object* dictionary) {
13485 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013486 ASSERT(dictionary != NULL);
13487 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13488 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013489 Object* name_symbol;
13490 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013491 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013492 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13493 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013494 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013495 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13496 String::cast(name_symbol),
13497 Smi::FromInt(i),
13498 PropertyDetails(NONE, NORMAL));
13499 if (!maybe_dictionary->ToObject(&dictionary)) {
13500 // Non-recoverable failure. Calling code must restart heap
13501 // initialization.
13502 return maybe_dictionary;
13503 }
13504 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013505 }
13506 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013507}
13508
13509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013510const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13511 Heap* heap = name->GetHeap();
13512 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013513 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013514 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013515 int function_index = Smi::cast(smi_index)->value();
13516 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013517 }
13518 return NULL;
13519}
13520
13521
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013522const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013523 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13524}
13525
13526
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013527void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013528 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013529 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013530 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013531 if (isolate->heap()->new_space()->AddFreshPage()) {
13532 return;
13533 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013534 // Try to do a garbage collection; ignore it if it fails. The C
13535 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013536 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013537 } else {
13538 // Handle last resort GC and make sure to allow future allocations
13539 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013540 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013541 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013542 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013543}
13544
13545
13546} } // namespace v8::internal